W1: fix deadlocks and remove w1_control_thread
w1_control_thread was removed which would wake up every second and process
newly registered family codes and complete some final cleanup for a
removed master. Those routines were moved to the threads that were
previously requesting those operations. A new function
w1_reconnect_slaves takes care of reconnecting existing slave devices when
a new family code is registered or removed. The removal case was missing
and would cause a deadlock waiting for the family code reference count to
decrease, which will now happen. A problem with registering a family code
was fixed. A slave device would be unattached if it wasn't yet claimed,
then attached at the end of the list, two unclaimed slaves would cause an
infinite loop.
The struct w1_bus_master.search now takes a pointer to the struct
w1_master device to avoid searching for it, which would have caused a
lock ordering deadlock with the removal of w1_control_thread.
Signed-off-by: David Fries <david@fries.net>
Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 6840dfe..ed32280 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -148,10 +148,22 @@
void __w1_remove_master_device(struct w1_master *dev)
{
struct w1_netlink_msg msg;
+ struct w1_slave *sl, *sln;
set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
kthread_stop(dev->thread);
+ mutex_lock(&w1_mlock);
+ list_del(&dev->w1_master_entry);
+ mutex_unlock(&w1_mlock);
+
+ mutex_lock(&dev->mutex);
+ list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry)
+ w1_slave_detach(sl);
+ w1_destroy_master_attributes(dev);
+ mutex_unlock(&dev->mutex);
+ atomic_dec(&dev->refcnt);
+
while (atomic_read(&dev->refcnt)) {
dev_info(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n",
dev->name, atomic_read(&dev->refcnt));