public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] driver core: separate function to shutdown one device
  2026-03-19 14:11 [PATCH v12 0/5] shut down devices asynchronously David Jeffery
@ 2026-03-19 14:11 ` David Jeffery
  0 siblings, 0 replies; 13+ messages in thread
From: David Jeffery @ 2026-03-19 14:11 UTC (permalink / raw)
  To: linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
  Cc: Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	David Jeffery

Make a separate function for the part of device_shutdown() that does the
shutown for a single device.  This is in preparation for making device
shutdown asynchronous.

Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com>
Signed-off-by: David Jeffery <djeffery@redhat.com>
Tested-by: Laurence Oberman <loberman@redhat.com>
---
 drivers/base/core.c | 71 +++++++++++++++++++++++++--------------------
 1 file changed, 39 insertions(+), 32 deletions(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index 791f9e444df8..10586298e18b 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -4782,12 +4782,48 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid)
 	return error;
 }
 
+static void shutdown_one_device(struct device *dev)
+{
+	struct device *parent = dev->parent;
+
+	/* hold lock to avoid race with probe/release */
+	if (parent)
+		device_lock(parent);
+	device_lock(dev);
+
+	/* Don't allow any more runtime suspends */
+	pm_runtime_get_noresume(dev);
+	pm_runtime_barrier(dev);
+
+	if (dev->class && dev->class->shutdown_pre) {
+		if (initcall_debug)
+			dev_info(dev, "shutdown_pre\n");
+		dev->class->shutdown_pre(dev);
+	}
+	if (dev->bus && dev->bus->shutdown) {
+		if (initcall_debug)
+			dev_info(dev, "shutdown\n");
+		dev->bus->shutdown(dev);
+	} else if (dev->driver && dev->driver->shutdown) {
+		if (initcall_debug)
+			dev_info(dev, "shutdown\n");
+		dev->driver->shutdown(dev);
+	}
+
+	device_unlock(dev);
+	if (parent)
+		device_unlock(parent);
+
+	put_device(parent);
+	put_device(dev);
+}
+
 /**
  * device_shutdown - call ->shutdown() on each device to shutdown.
  */
 void device_shutdown(void)
 {
-	struct device *dev, *parent;
+	struct device *dev;
 
 	wait_for_device_probe();
 	device_block_probing();
@@ -4809,7 +4845,7 @@ void device_shutdown(void)
 		 * prevent it from being freed because parent's
 		 * lock is to be held
 		 */
-		parent = get_device(dev->parent);
+		get_device(dev->parent);
 		get_device(dev);
 		/*
 		 * Make sure the device is off the kset list, in the
@@ -4818,36 +4854,7 @@ void device_shutdown(void)
 		list_del_init(&dev->kobj.entry);
 		spin_unlock(&devices_kset->list_lock);
 
-		/* hold lock to avoid race with probe/release */
-		if (parent)
-			device_lock(parent);
-		device_lock(dev);
-
-		/* Don't allow any more runtime suspends */
-		pm_runtime_get_noresume(dev);
-		pm_runtime_barrier(dev);
-
-		if (dev->class && dev->class->shutdown_pre) {
-			if (initcall_debug)
-				dev_info(dev, "shutdown_pre\n");
-			dev->class->shutdown_pre(dev);
-		}
-		if (dev->bus && dev->bus->shutdown) {
-			if (initcall_debug)
-				dev_info(dev, "shutdown\n");
-			dev->bus->shutdown(dev);
-		} else if (dev->driver && dev->driver->shutdown) {
-			if (initcall_debug)
-				dev_info(dev, "shutdown\n");
-			dev->driver->shutdown(dev);
-		}
-
-		device_unlock(dev);
-		if (parent)
-			device_unlock(parent);
-
-		put_device(dev);
-		put_device(parent);
+		shutdown_one_device(dev);
 
 		spin_lock(&devices_kset->list_lock);
 	}
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v13 0/5] shut down devices asynchronously
@ 2026-04-07 15:35 David Jeffery
  2026-04-07 15:35 ` [PATCH 1/5] driver core: separate function to shutdown one device David Jeffery
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: David Jeffery @ 2026-04-07 15:35 UTC (permalink / raw)
  To: linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
  Cc: Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	Martin K . Petersen, David Jeffery

This patchset allows the kernel to shutdown devices asynchronously and
unrelated async devices to be shut down in parallel to each other.

Only devices which explicitly enable it are shut down asynchronously. The
default is for a device to be shut down from the synchronous shutdown loop.

This can dramatically reduce system shutdown/reboot time on systems that
have multiple devices that take many seconds to shut down (like certain
NVMe drives). On one system tested, the shutdown time went from 11 minutes
without this patch to 55 seconds with the patch. And on another system from
80 seconds to 11.

Changes from V12:

Only acquire a parent reference if acquiring the parent's lock
device_enable_async_shutdown should return void
Minor comment and description cleanups

Changes from V11:

  * Swap the order of the first two patches
  * Rework conditional parent locking so that lock and unlock no longer use
    separate conditional checks
  * Remove an used variable
  * Comment and description text cleanups

Changes from V10:

Reworked to more closely match the design used for async suspend
  * No longer uses async subsystem cookies for synchronization
  * Minimized changes to struct device
  * Enable async shutdown for pci and scsi devices which support async suspend

Changes from V9:

Address resource and timing issues when spawning a unique async thread
for every device during shutdown:
  * Make the asynchronous threads able to shut down multiple devices,
    instead of spawning a unique thread for every device.
  * Modify core kernel async code with a custom wake function so it
    doesn't wake up a thread waiting to synchronize on a cookie until
    the cookie has reached the desired value, instead of waking up
    every waiting thread to check the cookie every time an async thread
    ends.

Changes from V8:

Deal with shutdown hangs resulting when a parent/supplier device is
  later in the devices_kset list than its children/consumers:
  * Ignore sync_state_only devlinks for shutdown dependencies
  * Ignore shutdown_after for devices that don't want async shutdown
  * Add a sanity check to revert to sync shutdown for any device that
    would otherwise wait for a child/consumer shutdown that hasn't
    already been scheduled

Changes from V7:

Do not expose driver async_shutdown_enable in sysfs.
Wrapped a long line.

Changes from V6:

Removed a sysfs attribute that allowed the async device shutdown to be
"on" (with driver opt-out), "safe" (driver opt-in), or "off"... what was
previously "safe" is now the only behavior, so drivers now only need to
have the option to enable or disable async shutdown.

Changes from V5:

Separated into multiple patches to make review easier.
Reworked some code to make it more readable
Made devices wait for consumers to shut down, not just children
  (suggested by David Jeffery)

Changes from V4:

Change code to use cookies for synchronization rather than async domains
Allow async shutdown to be disabled via sysfs, and allow driver opt-in or
  opt-out of async shutdown (when not disabled), with ability to control
  driver opt-in/opt-out via sysfs
  
Changes from V3:

Bug fix (used "parent" not "dev->parent" in device_shutdown)
 
Changes from V2:
 
Removed recursive functions to schedule children to be shutdown before
  parents, since existing device_shutdown loop will already do this
 
Changes from V1:

Rewritten using kernel async code (suggested by Lukas Wunner)


Stuart Hayes (2):
  driver core: separate function to shutdown one device
  driver core: do not always lock parent in shutdown

David Jeffery (3):
  driver core: async device shutdown infrastructure
  PCI: Enable async shutdown support
  scsi: enable async shutdown support

 drivers/base/base.h       |   2 +
 drivers/base/core.c       | 180 ++++++++++++++++++++++++++++++--------
 drivers/pci/probe.c       |   2 +
 drivers/scsi/hosts.c      |   3 +
 drivers/scsi/scsi_scan.c  |   1 +
 drivers/scsi/scsi_sysfs.c |   4 +
 include/linux/device.h    |  13 +++
 7 files changed, 169 insertions(+), 36 deletions(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/5] driver core: separate function to shutdown one device
  2026-04-07 15:35 [PATCH v13 0/5] shut down devices asynchronously David Jeffery
@ 2026-04-07 15:35 ` David Jeffery
  2026-04-07 15:35 ` [PATCH 2/5] driver core: do not always lock parent in shutdown David Jeffery
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: David Jeffery @ 2026-04-07 15:35 UTC (permalink / raw)
  To: linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
  Cc: Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	Martin K . Petersen, David Jeffery

Make a separate function for the part of device_shutdown() that does the
shutown for a single device.  This is in preparation for making device
shutdown asynchronous.

Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com>
Signed-off-by: David Jeffery <djeffery@redhat.com>
Tested-by: Laurence Oberman <loberman@redhat.com>
---
 drivers/base/core.c | 71 +++++++++++++++++++++++++--------------------
 1 file changed, 39 insertions(+), 32 deletions(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index 09b98f02f559..fabd17be1175 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -4784,12 +4784,48 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid)
 	return error;
 }
 
+static void shutdown_one_device(struct device *dev)
+{
+	struct device *parent = dev->parent;
+
+	/* hold lock to avoid race with probe/release */
+	if (parent)
+		device_lock(parent);
+	device_lock(dev);
+
+	/* Don't allow any more runtime suspends */
+	pm_runtime_get_noresume(dev);
+	pm_runtime_barrier(dev);
+
+	if (dev->class && dev->class->shutdown_pre) {
+		if (initcall_debug)
+			dev_info(dev, "shutdown_pre\n");
+		dev->class->shutdown_pre(dev);
+	}
+	if (dev->bus && dev->bus->shutdown) {
+		if (initcall_debug)
+			dev_info(dev, "shutdown\n");
+		dev->bus->shutdown(dev);
+	} else if (dev->driver && dev->driver->shutdown) {
+		if (initcall_debug)
+			dev_info(dev, "shutdown\n");
+		dev->driver->shutdown(dev);
+	}
+
+	device_unlock(dev);
+	if (parent)
+		device_unlock(parent);
+
+	put_device(parent);
+	put_device(dev);
+}
+
 /**
  * device_shutdown - call ->shutdown() on each device to shutdown.
  */
 void device_shutdown(void)
 {
-	struct device *dev, *parent;
+	struct device *dev;
 
 	wait_for_device_probe();
 	device_block_probing();
@@ -4811,7 +4847,7 @@ void device_shutdown(void)
 		 * prevent it from being freed because parent's
 		 * lock is to be held
 		 */
-		parent = get_device(dev->parent);
+		get_device(dev->parent);
 		get_device(dev);
 		/*
 		 * Make sure the device is off the kset list, in the
@@ -4820,36 +4856,7 @@ void device_shutdown(void)
 		list_del_init(&dev->kobj.entry);
 		spin_unlock(&devices_kset->list_lock);
 
-		/* hold lock to avoid race with probe/release */
-		if (parent)
-			device_lock(parent);
-		device_lock(dev);
-
-		/* Don't allow any more runtime suspends */
-		pm_runtime_get_noresume(dev);
-		pm_runtime_barrier(dev);
-
-		if (dev->class && dev->class->shutdown_pre) {
-			if (initcall_debug)
-				dev_info(dev, "shutdown_pre\n");
-			dev->class->shutdown_pre(dev);
-		}
-		if (dev->bus && dev->bus->shutdown) {
-			if (initcall_debug)
-				dev_info(dev, "shutdown\n");
-			dev->bus->shutdown(dev);
-		} else if (dev->driver && dev->driver->shutdown) {
-			if (initcall_debug)
-				dev_info(dev, "shutdown\n");
-			dev->driver->shutdown(dev);
-		}
-
-		device_unlock(dev);
-		if (parent)
-			device_unlock(parent);
-
-		put_device(dev);
-		put_device(parent);
+		shutdown_one_device(dev);
 
 		spin_lock(&devices_kset->list_lock);
 	}
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/5] driver core: do not always lock parent in shutdown
  2026-04-07 15:35 [PATCH v13 0/5] shut down devices asynchronously David Jeffery
  2026-04-07 15:35 ` [PATCH 1/5] driver core: separate function to shutdown one device David Jeffery
@ 2026-04-07 15:35 ` David Jeffery
  2026-04-07 15:35 ` [PATCH 3/5] driver core: async device shutdown infrastructure David Jeffery
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: David Jeffery @ 2026-04-07 15:35 UTC (permalink / raw)
  To: linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
  Cc: Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	Martin K . Petersen, David Jeffery

Don't lock a parent device unless it is needed in device_shutdown. This
is in preparation for making device shutdown asynchronous, when it will
be needed to allow children of a common parent to shut down
simultaneously.

And only acquire a reference to the parent device if the parent is to be
locked.

Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com>
Signed-off-by: David Jeffery <djeffery@redhat.com>
Tested-by: Laurence Oberman <loberman@redhat.com>
---
 drivers/base/core.c | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index fabd17be1175..0fb2f3ccc3bd 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -4784,13 +4784,8 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid)
 	return error;
 }
 
-static void shutdown_one_device(struct device *dev)
+static void __shutdown_one_device(struct device *dev)
 {
-	struct device *parent = dev->parent;
-
-	/* hold lock to avoid race with probe/release */
-	if (parent)
-		device_lock(parent);
 	device_lock(dev);
 
 	/* Don't allow any more runtime suspends */
@@ -4813,10 +4808,23 @@ static void shutdown_one_device(struct device *dev)
 	}
 
 	device_unlock(dev);
-	if (parent)
+}
+
+static void shutdown_one_device(struct device *dev)
+{
+	struct device *parent;
+
+	/* hold lock if needed to avoid race with probe/release */
+	if (dev->bus && dev->bus->need_parent_lock &&
+	    (parent = get_device(dev->parent))) {
+		device_lock(parent);
+		__shutdown_one_device(dev);
 		device_unlock(parent);
+		put_device(parent);
+	} else {
+		__shutdown_one_device(dev);
+	}
 
-	put_device(parent);
 	put_device(dev);
 }
 
@@ -4842,12 +4850,6 @@ void device_shutdown(void)
 		dev = list_entry(devices_kset->list.prev, struct device,
 				kobj.entry);
 
-		/*
-		 * hold reference count of device's parent to
-		 * prevent it from being freed because parent's
-		 * lock is to be held
-		 */
-		get_device(dev->parent);
 		get_device(dev);
 		/*
 		 * Make sure the device is off the kset list, in the
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/5] driver core: async device shutdown infrastructure
  2026-04-07 15:35 [PATCH v13 0/5] shut down devices asynchronously David Jeffery
  2026-04-07 15:35 ` [PATCH 1/5] driver core: separate function to shutdown one device David Jeffery
  2026-04-07 15:35 ` [PATCH 2/5] driver core: do not always lock parent in shutdown David Jeffery
@ 2026-04-07 15:35 ` David Jeffery
  2026-04-07 15:35 ` [PATCH 4/5] PCI: Enable async shutdown support David Jeffery
  2026-04-07 15:35 ` [PATCH 5/5] scsi: enable " David Jeffery
  4 siblings, 0 replies; 13+ messages in thread
From: David Jeffery @ 2026-04-07 15:35 UTC (permalink / raw)
  To: linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
  Cc: Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	Martin K . Petersen, David Jeffery

Patterned after async suspend, allow devices to mark themselves as wanting
to perform async shutdown. Devices using async shutdown wait only for their
dependencies to shutdown before executing their shutdown routine.

Sync shutdown devices are shut down one at a time and will only wait for an
async shutdown device if the async device is a dependency.

Signed-off-by: David Jeffery <djeffery@redhat.com>
Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com>
Tested-by: Laurence Oberman <loberman@redhat.com>
---
 drivers/base/base.h    |   2 +
 drivers/base/core.c    | 101 ++++++++++++++++++++++++++++++++++++++++-
 include/linux/device.h |  13 ++++++
 3 files changed, 115 insertions(+), 1 deletion(-)

diff --git a/drivers/base/base.h b/drivers/base/base.h
index 1af95ac68b77..cd435adeeac5 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -113,6 +113,7 @@ struct driver_type {
  * @device - pointer back to the struct device that this structure is
  * associated with.
  * @driver_type - The type of the bound Rust driver.
+ * @complete - completion for device shutdown ordering
  * @dead - This device is currently either in the process of or has been
  *	removed from the system. Any asynchronous events scheduled for this
  *	device should exit without taking any action.
@@ -132,6 +133,7 @@ struct device_private {
 #ifdef CONFIG_RUST
 	struct driver_type driver_type;
 #endif
+	struct completion complete;
 	u8 dead:1;
 };
 #define to_device_private_parent(obj)	\
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 0fb2f3ccc3bd..89b482435e85 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/async.h>
 #include <linux/blkdev.h>
 #include <linux/cleanup.h>
 #include <linux/cpufreq.h>
@@ -37,6 +38,10 @@
 #include "physical_location.h"
 #include "power/power.h"
 
+static bool async_shutdown = true;
+module_param(async_shutdown, bool, 0644);
+MODULE_PARM_DESC(async_shutdown, "Enable asynchronous device shutdown support");
+
 /* Device links support. */
 static LIST_HEAD(deferred_sync);
 static unsigned int defer_sync_state_count = 1;
@@ -3540,6 +3545,7 @@ static int device_private_init(struct device *dev)
 	klist_init(&dev->p->klist_children, klist_children_get,
 		   klist_children_put);
 	INIT_LIST_HEAD(&dev->p->deferred_probe);
+	init_completion(&dev->p->complete);
 	return 0;
 }
 
@@ -4784,6 +4790,37 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid)
 	return error;
 }
 
+static bool wants_async_shutdown(struct device *dev)
+{
+	return async_shutdown && dev->async_shutdown;
+}
+
+static int wait_for_device_shutdown(struct device *dev, void *data)
+{
+	bool async = *(bool *)data;
+
+	if (async || wants_async_shutdown(dev))
+		wait_for_completion(&dev->p->complete);
+
+	return 0;
+}
+
+static void wait_for_shutdown_dependencies(struct device *dev, bool async)
+{
+	struct device_link *link;
+	int idx;
+
+	device_for_each_child(dev, &async, wait_for_device_shutdown);
+
+	idx = device_links_read_lock();
+
+	dev_for_each_link_to_consumer(link, dev)
+		if (!device_link_flag_is_sync_state_only(link->flags))
+			wait_for_device_shutdown(link->consumer, &async);
+
+	device_links_read_unlock(idx);
+}
+
 static void __shutdown_one_device(struct device *dev)
 {
 	device_lock(dev);
@@ -4807,6 +4844,8 @@ static void __shutdown_one_device(struct device *dev)
 		dev->driver->shutdown(dev);
 	}
 
+	complete_all(&dev->p->complete);
+
 	device_unlock(dev);
 }
 
@@ -4828,6 +4867,55 @@ static void shutdown_one_device(struct device *dev)
 	put_device(dev);
 }
 
+static void async_shutdown_handler(void *data, async_cookie_t cookie)
+{
+	struct device *dev = data;
+
+	wait_for_shutdown_dependencies(dev, true);
+	shutdown_one_device(dev);
+}
+
+static bool shutdown_device_async(struct device *dev)
+{
+	if (async_schedule_dev_nocall(async_shutdown_handler, dev))
+		return true;
+	return false;
+}
+
+
+static void early_async_shutdown_devices(void)
+{
+	struct device *dev, *next, *needs_put = NULL;
+
+	if (!async_shutdown)
+		return;
+
+	spin_lock(&devices_kset->list_lock);
+
+	list_for_each_entry_safe_reverse(dev, next, &devices_kset->list,
+					 kobj.entry) {
+		if (wants_async_shutdown(dev)) {
+			get_device(dev);
+
+			if (shutdown_device_async(dev)) {
+				list_del_init(&dev->kobj.entry);
+			} else {
+				/*
+				 * async failed, clean up extra references
+				 * and run from the standard shutdown loop
+				 */
+				needs_put = dev;
+				break;
+			}
+		}
+	}
+
+	spin_unlock(&devices_kset->list_lock);
+
+	if (needs_put)
+		put_device(needs_put);
+}
+
 /**
  * device_shutdown - call ->shutdown() on each device to shutdown.
  */
@@ -4840,6 +4928,12 @@ void device_shutdown(void)
 
 	cpufreq_suspend();
 
+	/*
+	 * Start async device threads where possible to maximize potential
+	 * parallelism and minimize false dependency on unrelated sync devices
+	 */
+	early_async_shutdown_devices();
+
 	spin_lock(&devices_kset->list_lock);
 	/*
 	 * Walk the devices list backward, shutting down each in turn.
@@ -4858,11 +4952,16 @@ void device_shutdown(void)
 		list_del_init(&dev->kobj.entry);
 		spin_unlock(&devices_kset->list_lock);
 
-		shutdown_one_device(dev);
+		if (!wants_async_shutdown(dev) || !shutdown_device_async(dev)) {
+			wait_for_shutdown_dependencies(dev, false);
+			shutdown_one_device(dev);
+		}
 
 		spin_lock(&devices_kset->list_lock);
 	}
 	spin_unlock(&devices_kset->list_lock);
+
+	async_synchronize_full();
 }
 
 /*
diff --git a/include/linux/device.h b/include/linux/device.h
index e65d564f01cd..cdc890e5d6ae 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -553,6 +553,8 @@ struct device_physical_location {
  * @dma_skip_sync: DMA sync operations can be skipped for coherent buffers.
  * @dma_iommu: Device is using default IOMMU implementation for DMA and
  *		doesn't rely on dma_ops structure.
+ * @async_shutdown: Device shutdown may be run asynchronously and in parallel
+ *		to the shutdown of unrelated devices
  *
  * At the lowest level, every device in a Linux system is represented by an
  * instance of struct device. The device structure contains the information
@@ -675,6 +677,7 @@ struct device {
 #ifdef CONFIG_IOMMU_DMA
 	bool			dma_iommu:1;
 #endif
+	bool			async_shutdown:1;
 };
 
 /**
@@ -878,6 +881,16 @@ static inline bool device_async_suspend_enabled(struct device *dev)
 	return !!dev->power.async_suspend;
 }
 
+static inline void device_enable_async_shutdown(struct device *dev)
+{
+	dev->async_shutdown = true;
+}
+
+static inline bool device_async_shutdown_enabled(struct device *dev)
+{
+	return !!dev->async_shutdown;
+}
+
 static inline bool device_pm_not_required(struct device *dev)
 {
 	return dev->power.no_pm;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/5] PCI: Enable async shutdown support
  2026-04-07 15:35 [PATCH v13 0/5] shut down devices asynchronously David Jeffery
                   ` (2 preceding siblings ...)
  2026-04-07 15:35 ` [PATCH 3/5] driver core: async device shutdown infrastructure David Jeffery
@ 2026-04-07 15:35 ` David Jeffery
  2026-04-07 15:35 ` [PATCH 5/5] scsi: enable " David Jeffery
  4 siblings, 0 replies; 13+ messages in thread
From: David Jeffery @ 2026-04-07 15:35 UTC (permalink / raw)
  To: linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
  Cc: Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	Martin K . Petersen, David Jeffery

Like its async suspend support, allow PCI device shutdown to be performed
asynchronously to reduce shutdown time.

Signed-off-by: David Jeffery <djeffery@redhat.com>
Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com>
Tested-by: Laurence Oberman <loberman@redhat.com>
---
 drivers/pci/probe.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index bccc7a4bdd79..4d98bab2163d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1040,6 +1040,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
 
 	bus->bridge = get_device(&bridge->dev);
 	device_enable_async_suspend(bus->bridge);
+	device_enable_async_shutdown(bus->bridge);
 	pci_set_bus_of_node(bus);
 	pci_set_bus_msi_domain(bus);
 	if (bridge->msi_domain && !dev_get_msi_domain(&bus->dev) &&
@@ -2749,6 +2750,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
 	pci_reassigndev_resource_alignment(dev);
 
 	pci_init_capabilities(dev);
+	device_enable_async_shutdown(&dev->dev);
 
 	/*
 	 * Add the device to our list of discovered devices
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/5] scsi: enable async shutdown support
  2026-04-07 15:35 [PATCH v13 0/5] shut down devices asynchronously David Jeffery
                   ` (3 preceding siblings ...)
  2026-04-07 15:35 ` [PATCH 4/5] PCI: Enable async shutdown support David Jeffery
@ 2026-04-07 15:35 ` David Jeffery
  2026-04-07 16:34   ` John Garry
  4 siblings, 1 reply; 13+ messages in thread
From: David Jeffery @ 2026-04-07 15:35 UTC (permalink / raw)
  To: linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
  Cc: Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	Martin K . Petersen, David Jeffery

Like scsi's async suspend support, allow scsi devices to be shut down
asynchronously to reduce system shutdown time.

Signed-off-by: David Jeffery <djeffery@redhat.com>
Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com>
Tested-by: Laurence Oberman <loberman@redhat.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
---
 drivers/scsi/hosts.c      | 3 +++
 drivers/scsi/scsi_scan.c  | 1 +
 drivers/scsi/scsi_sysfs.c | 4 ++++
 3 files changed, 8 insertions(+)

diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index e047747d4ecf..dfb38a82c0bf 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -273,6 +273,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
 	pm_runtime_set_active(&shost->shost_gendev);
 	pm_runtime_enable(&shost->shost_gendev);
 	device_enable_async_suspend(&shost->shost_gendev);
+	device_enable_async_shutdown(&shost->shost_gendev);
 
 	error = device_add(&shost->shost_gendev);
 	if (error)
@@ -282,6 +283,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
 	get_device(shost->shost_gendev.parent);
 
 	device_enable_async_suspend(&shost->shost_dev);
+	device_enable_async_shutdown(&shost->shost_dev);
 
 	get_device(&shost->shost_gendev);
 	error = device_add(&shost->shost_dev);
@@ -519,6 +521,7 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv
 	shost->shost_gendev.bus = &scsi_bus_type;
 	shost->shost_gendev.type = &scsi_host_type;
 	scsi_enable_async_suspend(&shost->shost_gendev);
+	device_enable_async_shutdown(&shost->shost_gendev);
 
 	device_initialize(&shost->shost_dev);
 	shost->shost_dev.parent = &shost->shost_gendev;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 7b11bc7de0e3..72f30db8609a 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -515,6 +515,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
 	dev->bus = &scsi_bus_type;
 	dev->type = &scsi_target_type;
 	scsi_enable_async_suspend(dev);
+	device_enable_async_shutdown(dev);
 	starget->id = id;
 	starget->channel = channel;
 	starget->can_queue = 0;
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 6b8c5c05f294..c76ba17b206f 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1370,6 +1370,7 @@ static int scsi_target_add(struct scsi_target *starget)
 	pm_runtime_set_active(&starget->dev);
 	pm_runtime_enable(&starget->dev);
 	device_enable_async_suspend(&starget->dev);
+	device_enable_async_shutdown(&starget->dev);
 
 	return 0;
 }
@@ -1396,6 +1397,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 	transport_configure_device(&starget->dev);
 
 	device_enable_async_suspend(&sdev->sdev_gendev);
+	device_enable_async_shutdown(&sdev->sdev_gendev);
 	scsi_autopm_get_target(starget);
 	pm_runtime_set_active(&sdev->sdev_gendev);
 	if (!sdev->rpm_autosuspend)
@@ -1415,6 +1417,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 	}
 
 	device_enable_async_suspend(&sdev->sdev_dev);
+	device_enable_async_shutdown(&sdev->sdev_dev);
 	error = device_add(&sdev->sdev_dev);
 	if (error) {
 		sdev_printk(KERN_INFO, sdev,
@@ -1670,6 +1673,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
 	sdev->sdev_gendev.bus = &scsi_bus_type;
 	sdev->sdev_gendev.type = &scsi_dev_type;
 	scsi_enable_async_suspend(&sdev->sdev_gendev);
+	device_enable_async_shutdown(&sdev->sdev_gendev);
 	dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%llu",
 		     sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
 	sdev->sdev_gendev.groups = hostt->sdev_groups;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] scsi: enable async shutdown support
  2026-04-07 15:35 ` [PATCH 5/5] scsi: enable " David Jeffery
@ 2026-04-07 16:34   ` John Garry
  2026-04-08 14:16     ` David Jeffery
  0 siblings, 1 reply; 13+ messages in thread
From: John Garry @ 2026-04-07 16:34 UTC (permalink / raw)
  To: David Jeffery, linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
  Cc: Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	Martin K . Petersen


>   }
> @@ -1396,6 +1397,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
>   	transport_configure_device(&starget->dev);
>   
>   	device_enable_async_suspend(&sdev->sdev_gendev);
> +	device_enable_async_shutdown(&sdev->sdev_gendev);

We call device_enable_async_shutdown(&sdev->sdev_gendev) here and 
scsi_sysfs_device_initialize() - any reason for that?

>   	scsi_autopm_get_target(starget);
>   	pm_runtime_set_active(&sdev->sdev_gendev);
>   	if (!sdev->rpm_autosuspend)
> @@ -1415,6 +1417,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
>   	}
>   
>   	device_enable_async_suspend(&sdev->sdev_dev);
> +	device_enable_async_shutdown(&sdev->sdev_dev);
>   	error = device_add(&sdev->sdev_dev);
>   	if (error) {
>   		sdev_printk(KERN_INFO, sdev,
> @@ -1670,6 +1673,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
>   	sdev->sdev_gendev.bus = &scsi_bus_type;
>   	sdev->sdev_gendev.type = &scsi_dev_type;
>   	scsi_enable_async_suspend(&sdev->sdev_gendev);
> +	device_enable_async_shutdown(&sdev->sdev_gendev);
>   	dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%llu",
>   		     sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
>   	sdev->sdev_gendev.groups = hostt->sdev_groups;


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] scsi: enable async shutdown support
  2026-04-07 16:34   ` John Garry
@ 2026-04-08 14:16     ` David Jeffery
  2026-04-08 15:53       ` John Garry
  0 siblings, 1 reply; 13+ messages in thread
From: David Jeffery @ 2026-04-08 14:16 UTC (permalink / raw)
  To: John Garry
  Cc: linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	Martin K . Petersen

On Tue, Apr 7, 2026 at 12:35 PM John Garry <john.g.garry@oracle.com> wrote:
>
>
> >   }
> > @@ -1396,6 +1397,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
> >       transport_configure_device(&starget->dev);
> >
> >       device_enable_async_suspend(&sdev->sdev_gendev);
> > +     device_enable_async_shutdown(&sdev->sdev_gendev);
>
> We call device_enable_async_shutdown(&sdev->sdev_gendev) here and
> scsi_sysfs_device_initialize() - any reason for that?
>

It was added to match locations where async suspend is set. But as you
point out, it does appear redundant to use both locations.

David Jeffery


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] scsi: enable async shutdown support
  2026-04-08 14:16     ` David Jeffery
@ 2026-04-08 15:53       ` John Garry
  2026-04-08 19:35         ` David Jeffery
  0 siblings, 1 reply; 13+ messages in thread
From: John Garry @ 2026-04-08 15:53 UTC (permalink / raw)
  To: David Jeffery, bvanassche
  Cc: linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bart Van Assche, Bjorn Helgaas,
	Martin K . Petersen

On 08/04/2026 15:16, David Jeffery wrote:
> On Tue, Apr 7, 2026 at 12:35 PM John Garry<john.g.garry@oracle.com> wrote:
>>
>>>    }
>>> @@ -1396,6 +1397,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
>>>        transport_configure_device(&starget->dev);
>>>
>>>        device_enable_async_suspend(&sdev->sdev_gendev);
>>> +     device_enable_async_shutdown(&sdev->sdev_gendev);
>> We call device_enable_async_shutdown(&sdev->sdev_gendev) here and
>> scsi_sysfs_device_initialize() - any reason for that?
>>
> It was added to match locations where async suspend is set. 

Well it is not exactly like that. We have the following:

scsi_sysfs_add_sdev() -> device_enable_async_suspend(&sdev->sdev_gendev)

and

scsi_sysfs_device_initialize() -> 
scsi_enable_async_suspend(&sdev->sdev_gendev) -> 
device_enable_async_suspend(&sdev->sdev_gendev) when not async

Maybe similar needs to be done for this shutdown feature. AFICS, Bart, 
added scsi_enable_async_suspend(), so maybe he can comment.

Thanks,
John


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] scsi: enable async shutdown support
  2026-04-08 15:53       ` John Garry
@ 2026-04-08 19:35         ` David Jeffery
  2026-04-09 12:17           ` John Garry
  0 siblings, 1 reply; 13+ messages in thread
From: David Jeffery @ 2026-04-08 19:35 UTC (permalink / raw)
  To: John Garry
  Cc: bvanassche, linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bjorn Helgaas,
	Martin K . Petersen

On Wed, Apr 8, 2026 at 11:54 AM John Garry <john.g.garry@oracle.com> wrote:
>
> On 08/04/2026 15:16, David Jeffery wrote:
> > On Tue, Apr 7, 2026 at 12:35 PM John Garry<john.g.garry@oracle.com> wrote:
> >>
> >>>    }
> >>> @@ -1396,6 +1397,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
> >>>        transport_configure_device(&starget->dev);
> >>>
> >>>        device_enable_async_suspend(&sdev->sdev_gendev);
> >>> +     device_enable_async_shutdown(&sdev->sdev_gendev);
> >> We call device_enable_async_shutdown(&sdev->sdev_gendev) here and
> >> scsi_sysfs_device_initialize() - any reason for that?
> >>
> > It was added to match locations where async suspend is set.
>
> Well it is not exactly like that. We have the following:
>
> scsi_sysfs_add_sdev() -> device_enable_async_suspend(&sdev->sdev_gendev)
>
> and
>
> scsi_sysfs_device_initialize() ->
> scsi_enable_async_suspend(&sdev->sdev_gendev) ->
> device_enable_async_suspend(&sdev->sdev_gendev) when not async
>
> Maybe similar needs to be done for this shutdown feature. AFICS, Bart,
> added scsi_enable_async_suspend(), so maybe he can comment.
>

My inclination is to drop adding device_enable_async_shutdown into
scsi_sysfs_device_initialize. The intent is for normal scsi devices,
and I see little value in setting the flag so early to flag partially
initialized or pseudo devices.

David Jeffery


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] scsi: enable async shutdown support
  2026-04-08 19:35         ` David Jeffery
@ 2026-04-09 12:17           ` John Garry
  2026-04-09 20:36             ` David Jeffery
  0 siblings, 1 reply; 13+ messages in thread
From: John Garry @ 2026-04-09 12:17 UTC (permalink / raw)
  To: David Jeffery
  Cc: bvanassche, linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bjorn Helgaas,
	Martin K . Petersen

On 08/04/2026 20:35, David Jeffery wrote:
>> Well it is not exactly like that. We have the following:
>>
>> scsi_sysfs_add_sdev() -> device_enable_async_suspend(&sdev->sdev_gendev)
>>
>> and
>>
>> scsi_sysfs_device_initialize() ->
>> scsi_enable_async_suspend(&sdev->sdev_gendev) ->
>> device_enable_async_suspend(&sdev->sdev_gendev) when not async
>>
>> Maybe similar needs to be done for this shutdown feature. AFICS, Bart,
>> added scsi_enable_async_suspend(), so maybe he can comment.
>>
> My inclination is to drop adding device_enable_async_shutdown into
> scsi_sysfs_device_initialize. The intent is for normal scsi devices,
> and I see little value in setting the flag so early to flag partially
> initialized or pseudo devices.

That seems reasonable, but, again I am not so familiar with this async 
suspend and shutdown.

Thanks!

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/5] scsi: enable async shutdown support
  2026-04-09 12:17           ` John Garry
@ 2026-04-09 20:36             ` David Jeffery
  0 siblings, 0 replies; 13+ messages in thread
From: David Jeffery @ 2026-04-09 20:36 UTC (permalink / raw)
  To: John Garry
  Cc: bvanassche, linux-kernel, driver-core, linux-pci, linux-scsi,
	Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Tarun Sahu, Pasha Tatashin, Michał Cłapiński,
	Jordan Richards, Ewan Milne, John Meneghini, Lombardi, Maurizio,
	Stuart Hayes, Laurence Oberman, Bjorn Helgaas,
	Martin K . Petersen

On Thu, Apr 9, 2026 at 8:18 AM John Garry <john.g.garry@oracle.com> wrote:
>
> On 08/04/2026 20:35, David Jeffery wrote:
> >> Well it is not exactly like that. We have the following:
> >>
> >> scsi_sysfs_add_sdev() -> device_enable_async_suspend(&sdev->sdev_gendev)
> >>
> >> and
> >>
> >> scsi_sysfs_device_initialize() ->
> >> scsi_enable_async_suspend(&sdev->sdev_gendev) ->
> >> device_enable_async_suspend(&sdev->sdev_gendev) when not async
> >>
> >> Maybe similar needs to be done for this shutdown feature. AFICS, Bart,
> >> added scsi_enable_async_suspend(), so maybe he can comment.
> >>
> > My inclination is to drop adding device_enable_async_shutdown into
> > scsi_sysfs_device_initialize. The intent is for normal scsi devices,
> > and I see little value in setting the flag so early to flag partially
> > initialized or pseudo devices.
>
> That seems reasonable, but, again I am not so familiar with this async
> suspend and shutdown.
>

There also appears to be similar duplication with flagging scsi hosts
and targets for async shutdown. I'll see about consolidating those as
well.


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-04-09 20:37 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-07 15:35 [PATCH v13 0/5] shut down devices asynchronously David Jeffery
2026-04-07 15:35 ` [PATCH 1/5] driver core: separate function to shutdown one device David Jeffery
2026-04-07 15:35 ` [PATCH 2/5] driver core: do not always lock parent in shutdown David Jeffery
2026-04-07 15:35 ` [PATCH 3/5] driver core: async device shutdown infrastructure David Jeffery
2026-04-07 15:35 ` [PATCH 4/5] PCI: Enable async shutdown support David Jeffery
2026-04-07 15:35 ` [PATCH 5/5] scsi: enable " David Jeffery
2026-04-07 16:34   ` John Garry
2026-04-08 14:16     ` David Jeffery
2026-04-08 15:53       ` John Garry
2026-04-08 19:35         ` David Jeffery
2026-04-09 12:17           ` John Garry
2026-04-09 20:36             ` David Jeffery
  -- strict thread matches above, loose matches on Subject: below --
2026-03-19 14:11 [PATCH v12 0/5] shut down devices asynchronously David Jeffery
2026-03-19 14:11 ` [PATCH 1/5] driver core: separate function to shutdown one device David Jeffery

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox