aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-11-16 11:57:28 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-01-24 23:40:35 -0500
commitef2c51746dc89c2326ce522f8fb8a57695780e75 (patch)
tree80aacaea0a3124713f4cff5b14e5c98c97dd6b9b /drivers/base
parentc8e90d822bff3e0502d004facedb05859f98055f (diff)
Driver core: fix race in __device_release_driver
This patch (as1013) was suggested by David Woodhouse; it fixes a race in the driver core. If a device is unregistered at the same time as its driver is unloaded, the driver's code pages may be unmapped while the remove method is still running. The calls to get_driver() and put_driver() were intended to prevent this, but they don't work if the driver's module count has already dropped to 0. Instead, the patch keeps the device on the driver's list until after the remove method has returned. This forces the necessary synchronization to occur. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/dd.c5
1 files changed, 2 insertions, 3 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 54922647522d..b0726eb6405e 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -289,11 +289,10 @@ static void __device_release_driver(struct device * dev)
289{ 289{
290 struct device_driver * drv; 290 struct device_driver * drv;
291 291
292 drv = get_driver(dev->driver); 292 drv = dev->driver;
293 if (drv) { 293 if (drv) {
294 driver_sysfs_remove(dev); 294 driver_sysfs_remove(dev);
295 sysfs_remove_link(&dev->kobj, "driver"); 295 sysfs_remove_link(&dev->kobj, "driver");
296 klist_remove(&dev->knode_driver);
297 296
298 if (dev->bus) 297 if (dev->bus)
299 blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 298 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
@@ -306,7 +305,7 @@ static void __device_release_driver(struct device * dev)
306 drv->remove(dev); 305 drv->remove(dev);
307 devres_release_all(dev); 306 devres_release_all(dev);
308 dev->driver = NULL; 307 dev->driver = NULL;
309 put_driver(drv); 308 klist_remove(&dev->knode_driver);
310 } 309 }
311} 310}
312 311