|
@@ -1734,10 +1734,25 @@ EXPORT_SYMBOL_GPL(device_move);
|
|
|
*/
|
|
|
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) {
|
|
|
dev_dbg(dev, "shutdown\n");
|
|
|
dev->bus->shutdown(dev);
|
|
@@ -1745,6 +1760,10 @@ void device_shutdown(void)
|
|
|
dev_dbg(dev, "shutdown\n");
|
|
|
dev->driver->shutdown(dev);
|
|
|
}
|
|
|
+ put_device(dev);
|
|
|
+
|
|
|
+ spin_lock(&devices_kset->list_lock);
|
|
|
}
|
|
|
+ spin_unlock(&devices_kset->list_lock);
|
|
|
async_synchronize_full();
|
|
|
}
|