]> Pileus Git - ~andy/linux/blobdiff - drivers/net/netconsole.c
netconsole: avoid a crash with multiple sysfs writers
[~andy/linux] / drivers / net / netconsole.c
index 4822aafe638bf2a5b9504d803150b9e80a029318..dcb21347c67044da535903f2f88ba36f2529f347 100644 (file)
@@ -102,6 +102,7 @@ struct netconsole_target {
        struct config_item      item;
 #endif
        int                     enabled;
+       struct mutex            mutex;
        struct netpoll          np;
 };
 
@@ -181,6 +182,7 @@ static struct netconsole_target *alloc_param_target(char *target_config)
        strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
        nt->np.local_port = 6665;
        nt->np.remote_port = 6666;
+       mutex_init(&nt->mutex);
        memset(nt->np.remote_mac, 0xff, ETH_ALEN);
 
        /* Parse parameters and setup netpoll */
@@ -322,6 +324,7 @@ static ssize_t store_enabled(struct netconsole_target *nt,
                return -EINVAL;
        }
 
+       mutex_lock(&nt->mutex);
        if (enabled) {  /* 1 */
 
                /*
@@ -331,8 +334,10 @@ static ssize_t store_enabled(struct netconsole_target *nt,
                netpoll_print_options(&nt->np);
 
                err = netpoll_setup(&nt->np);
-               if (err)
+               if (err) {
+                       mutex_unlock(&nt->mutex);
                        return err;
+               }
 
                printk(KERN_INFO "netconsole: network logging started\n");
 
@@ -341,6 +346,7 @@ static ssize_t store_enabled(struct netconsole_target *nt,
        }
 
        nt->enabled = enabled;
+       mutex_unlock(&nt->mutex);
 
        return strnlen(buf, count);
 }
@@ -597,6 +603,7 @@ static struct config_item *make_netconsole_target(struct config_group *group,
        strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
        nt->np.local_port = 6665;
        nt->np.remote_port = 6666;
+       mutex_init(&nt->mutex);
        memset(nt->np.remote_mac, 0xff, ETH_ALEN);
 
        /* Initialize the config_item member */
@@ -682,7 +689,11 @@ restart:
                                 * we might sleep in __netpoll_cleanup()
                                 */
                                spin_unlock_irqrestore(&target_list_lock, flags);
+
+                               mutex_lock(&nt->mutex);
                                __netpoll_cleanup(&nt->np);
+                               mutex_unlock(&nt->mutex);
+
                                spin_lock_irqsave(&target_list_lock, flags);
                                dev_put(nt->np.dev);
                                nt->np.dev = NULL;