Driver core: Protect device shutdown from hot unplug events.
While device_shutdown() walks through devices_kset to shutdown all devices, device unplug events may race to shutdown individual devices. Specifically, sd_shutdown(), on behalf of fc_starget_delete(), has been observed deleting devices during device_shutdown()'s list traversal. So we factor out list_for_each_entry_safe_reverse(...) in favor of while (!list_empty(...)). Signed-off-by: Hugh Daschbach <hdasch@broadcom.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
e177123f0c
Коммит
6245838fe4
|
@ -1734,10 +1734,25 @@ EXPORT_SYMBOL_GPL(device_move);
|
||||||
*/
|
*/
|
||||||
void device_shutdown(void)
|
void device_shutdown(void)
|
||||||
{
|
{
|
||||||
struct device *dev, *devn;
|
struct device *dev;
|
||||||
|
|
||||||
|
spin_lock(&devices_kset->list_lock);
|
||||||
|
/*
|
||||||
|
* Walk the devices list backward, shutting down each in turn.
|
||||||
|
* Beware that device unplug events may also start pulling
|
||||||
|
* devices offline, even as the system is shutting down.
|
||||||
|
*/
|
||||||
|
while (!list_empty(&devices_kset->list)) {
|
||||||
|
dev = list_entry(devices_kset->list.prev, struct device,
|
||||||
|
kobj.entry);
|
||||||
|
get_device(dev);
|
||||||
|
/*
|
||||||
|
* Make sure the device is off the kset list, in the
|
||||||
|
* event that dev->*->shutdown() doesn't remove it.
|
||||||
|
*/
|
||||||
|
list_del_init(&dev->kobj.entry);
|
||||||
|
spin_unlock(&devices_kset->list_lock);
|
||||||
|
|
||||||
list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list,
|
|
||||||
kobj.entry) {
|
|
||||||
if (dev->bus && dev->bus->shutdown) {
|
if (dev->bus && dev->bus->shutdown) {
|
||||||
dev_dbg(dev, "shutdown\n");
|
dev_dbg(dev, "shutdown\n");
|
||||||
dev->bus->shutdown(dev);
|
dev->bus->shutdown(dev);
|
||||||
|
@ -1745,6 +1760,10 @@ void device_shutdown(void)
|
||||||
dev_dbg(dev, "shutdown\n");
|
dev_dbg(dev, "shutdown\n");
|
||||||
dev->driver->shutdown(dev);
|
dev->driver->shutdown(dev);
|
||||||
}
|
}
|
||||||
|
put_device(dev);
|
||||||
|
|
||||||
|
spin_lock(&devices_kset->list_lock);
|
||||||
}
|
}
|
||||||
|
spin_unlock(&devices_kset->list_lock);
|
||||||
async_synchronize_full();
|
async_synchronize_full();
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче