Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6245838f authored by Hugh Daschbach's avatar Hugh Daschbach Committed by Greg Kroah-Hartman
Browse files

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: default avatarHugh Daschbach <hdasch@broadcom.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent e177123f
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -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();
}