W1: Drop control thread from w1 core, whatever it does can also be done in the context of w1_remove_master_device. Also, pin the module when registering new master device to make sure that w1 core is not unloaded until last device is gone. This simplifies logic a lot. Signed-off-by: Dmitry Torokhov <dtor at mail.ru> --- w1.c | 157 +++++++++++++++---------------------------------------------------- w1.h | 1 2 files changed, 36 insertions(+), 122 deletions(-) Index: dtor/drivers/w1/w1.c =================================================================== --- dtor.orig/drivers/w1/w1.c +++ dtor/drivers/w1/w1.c @@ -50,14 +50,8 @@ module_param_named(timeout, w1_timeout, module_param_named(max_slave_count, w1_max_slave_count, int, 0); module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); -static DEFINE_SPINLOCK(w1_mlock); -static LIST_HEAD(w1_masters); static u32 w1_ids = 1; -static pid_t control_thread; -static int control_needs_exit; -static DECLARE_COMPLETION(w1_control_complete); - static int w1_master_match(struct device *dev, struct device_driver *drv) { return 1; @@ -582,66 +576,6 @@ void w1_search(struct w1_master *dev) } -static int w1_control(void *data) -{ - struct w1_slave *slave, *nexts; - struct w1_master *master, *nextm; - int err, have_to_wait = 0; - - daemonize("w1_control"); - allow_signal(SIGTERM); - - while (!control_needs_exit || have_to_wait) { - have_to_wait = 0; - - try_to_freeze(PF_FREEZE); - msleep_interruptible(w1_timeout * 1000); - - if (signal_pending(current)) - flush_signals(current); - - list_for_each_entry_safe(master, nextm, &w1_masters, node) { - - if (!control_needs_exit && !master->need_exit) - continue; - /* - * Little race: we can create thread but not set the flag. - * Get a chance for external process to set flag up. - */ - if (!master->initialized) { - have_to_wait = 1; - continue; - } - - spin_lock(&w1_mlock); - list_del(&master->node); - spin_unlock(&w1_mlock); - - if (control_needs_exit) { - master->need_exit = 1; - - err = kill_proc(master->kpid, SIGTERM, 1); - if (err) - dev_err(&master->dev, - "Failed to send signal to w1 kernel thread %d.\n", - master->kpid); - } - - wait_for_completion(&master->dev_exited); - - list_for_each_entry_safe(slave, nexts, &master->slist, node) { - list_del(&slave->node); - w1_slave_detach(slave); - kfree(slave); - } - w1_destroy_master_attributes(master); - atomic_dec(&master->refcnt); - } - } - - complete_and_exit(&w1_control_complete, 0); -} - static int w1_process(void *data) { struct w1_master *dev = (struct w1_master *) data; @@ -731,12 +665,22 @@ struct w1_master *w1_allocate_master_dev return dev; } -static void w1_free_dev(struct w1_master *dev) +static void w1_free_master_dev(struct w1_master *dev) { device_unregister(&dev->dev); kfree(dev); } +static void w1_stop_master_device(struct w1_master *dev) +{ + dev->need_exit = 1; + if (kill_proc(dev->kpid, SIGTERM, 1)) + dev_err(&dev->dev, + "Failed to send signal to w1 kernel thread %d.\n", + dev->kpid); + wait_for_completion(&dev->dev_exited); +} + int w1_add_master_device(struct w1_master *dev) { int error; @@ -762,36 +706,32 @@ int w1_add_master_device(struct w1_maste dev->initialized = 1; - spin_lock(&w1_mlock); - list_add(&dev->node, &w1_masters); - spin_unlock(&w1_mlock); + __module_get(THIS_MODULE); return 0; err_out_kill_thread: - dev->need_exit = 1; - if (kill_proc(dev->kpid, SIGTERM, 1)) - dev_err(&dev->dev, - "Failed to send signal to w1 kernel thread %d.\n", - dev->kpid); - wait_for_completion(&dev->dev_exited); + w1_stop_master_device(dev); err_out_free_dev: - w1_free_dev(dev); + w1_free_master_dev(dev); return error; } void w1_remove_master_device(struct w1_master *dev) { - int err; + struct w1_slave *slave, *next; - dev->need_exit = 1; - err = kill_proc(dev->kpid, SIGTERM, 1); - if (err) - dev_err(&dev->dev, - "%s: Failed to send signal to w1 kernel thread %d.\n", - __func__, dev->kpid); + w1_stop_master_device(dev); + + list_for_each_entry_safe(slave, next, &dev->slist, node) { + list_del(&slave->node); + w1_slave_detach(slave); + kfree(slave); + } + + w1_destroy_master_attributes(dev); while (atomic_read(&dev->refcnt)) { printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n", @@ -801,61 +741,36 @@ void w1_remove_master_device(struct w1_m flush_signals(current); } - w1_free_dev(dev); + w1_free_master_dev(dev); + module_put(THIS_MODULE); } int w1_init(void) { - int retval; + int error; printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); - retval = bus_register(&w1_bus_type); - if (retval) { - printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); - goto err_out_exit_init; + error = bus_register(&w1_bus_type); + if (error) { + printk(KERN_ERR "Failed to register bus. err=%d.\n", error); + return error; } - retval = driver_register(&w1_driver); - if (retval) { + error = driver_register(&w1_driver); + if (error) { printk(KERN_ERR - "Failed to register master driver. err=%d.\n", - retval); - goto err_out_bus_unregister; - } - - control_thread = kernel_thread(&w1_control, NULL, 0); - if (control_thread < 0) { - printk(KERN_ERR "Failed to create control thread. err=%d\n", - control_thread); - retval = control_thread; - goto err_out_driver_unregister; + "Failed to register master driver. err=%d.\n", error); + bus_unregister(&w1_bus_type); + return error; } return 0; - -err_out_driver_unregister: - driver_unregister(&w1_driver); - -err_out_bus_unregister: - bus_unregister(&w1_bus_type); - -err_out_exit_init: - return retval; } void w1_fini(void) { - struct w1_master *master, *next; - - list_for_each_entry_safe(master, next, &w1_masters, node) - w1_remove_master_device(master); - - control_needs_exit = 1; - - wait_for_completion(&w1_control_complete); - driver_unregister(&w1_driver); bus_unregister(&w1_bus_type); } Index: dtor/drivers/w1/w1.h =================================================================== --- dtor.orig/drivers/w1/w1.h +++ dtor/drivers/w1/w1.h @@ -103,7 +103,6 @@ struct w1_bus_ops struct w1_master { - struct list_head node; unsigned char name[W1_MAXNAMELEN]; struct list_head slist; int max_slave_count, slave_count;