Commit ef2c5174 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent c8e90d82
...@@ -289,11 +289,10 @@ static void __device_release_driver(struct device * dev) ...@@ -289,11 +289,10 @@ static void __device_release_driver(struct device * dev)
{ {
struct device_driver * drv; struct device_driver * drv;
drv = get_driver(dev->driver); drv = dev->driver;
if (drv) { if (drv) {
driver_sysfs_remove(dev); driver_sysfs_remove(dev);
sysfs_remove_link(&dev->kobj, "driver"); sysfs_remove_link(&dev->kobj, "driver");
klist_remove(&dev->knode_driver);
if (dev->bus) if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier, blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
...@@ -306,7 +305,7 @@ static void __device_release_driver(struct device * dev) ...@@ -306,7 +305,7 @@ static void __device_release_driver(struct device * dev)
drv->remove(dev); drv->remove(dev);
devres_release_all(dev); devres_release_all(dev);
dev->driver = NULL; dev->driver = NULL;
put_driver(drv); klist_remove(&dev->knode_driver);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment