From: Roman Kagan <rkagan@mail.ru>
Date: Wed, 13 Apr 2005 17:40:17 +0000 (+0400)
Subject: [PATCH] drivers/base/bus.c: fix iteration in driver_detach()
X-Git-Tag: firefly_0821_release~43393^2
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b2d84f078a8be40f5ae3b4d2ac001e2a7f45fe4f;p=firefly-linux-kernel-4.4.55.git

[PATCH] drivers/base/bus.c: fix iteration in driver_detach()

With 2.6.11 and 2.6.12-rc2 (and perhaps a few versions before) usb
drivers for multi-interface devices, which do
usb_driver_release_interface() in their disconnect(), make rmmod hang.

It turns out to be due to a bug in drivers/base/bus.c:driver_detach(),
that iterates over the list of attached devices with
list_for_each_safe() under an assumption that device_release_driver()
only releases the current device, while it may also call
device_release_driver() for other devices on the same list.

The following patch fixes it.  Please consider applying.

Signed-off-by: Roman Kagan <rkagan@mail.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---

diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index f4fa27315fb4..2b3902c867da 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -405,9 +405,8 @@ void device_release_driver(struct device * dev)
 
 static void driver_detach(struct device_driver * drv)
 {
-	struct list_head * entry, * next;
-	list_for_each_safe(entry, next, &drv->devices) {
-		struct device * dev = container_of(entry, struct device, driver_list);
+	while (!list_empty(&drv->devices)) {
+		struct device * dev = container_of(drv->devices.next, struct device, driver_list);
 		device_release_driver(dev);
 	}
 }