[PATCHv2 2/3] nvme-multipath: rescan siblings on last path removal

Keith Busch kbusch at meta.com
Thu Feb 26 10:32:15 PST 2026


From: Keith Busch <kbusch at kernel.org>

When a controller's scan removes the last path to a multipath namespace
head, sibling controllers in the same subsystem may need to rescan. A
concurrent scan on another controller could have encountered the stale
head with mismatched identifiers (e.g. from a recycled NSID) and failed
to set up the namespace. Without notification, the sibling won't retry
until the next AEN or explicit rescan.

After a scan that performed last-path removals, notify all controllers
in the subsystem to rescan by requeueing their scan work. This ensures
that recycled NSIDs are promptly discovered by sibling controllers.

Signed-off-by: Keith Busch <kbusch at kernel.org>
---
 drivers/nvme/host/core.c | 19 ++++++++++++++++++-
 drivers/nvme/host/nvme.h |  1 +
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 3de52f1d27234..5bb4b18511b7b 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -4262,8 +4262,10 @@ static void nvme_ns_remove(struct nvme_ns *ns)
 	mutex_unlock(&ns->ctrl->namespaces_lock);
 	synchronize_srcu(&ns->ctrl->srcu);
 
-	if (last_path)
+	if (last_path) {
 		nvme_mpath_remove_disk(ns->head);
+		set_bit(NVME_CTRL_SCAN_REMOVED_NS, &ns->ctrl->flags);
+	}
 	nvme_put_ns(ns);
 }
 
@@ -4530,6 +4532,21 @@ static void nvme_scan_work(struct work_struct *work)
 	}
 	mutex_unlock(&ctrl->scan_lock);
 
+	/*
+	 * If the scan removed the last path to a namespace, notify all
+	 * controllers in the subsystem to rescan. A controller that is
+	 * concurrently scanning may have missed the namespace due to the
+	 * stale head still occupying the NSID in the subsystem list.
+	 */
+	if (test_and_clear_bit(NVME_CTRL_SCAN_REMOVED_NS, &ctrl->flags)) {
+		struct nvme_ctrl *tmp;
+
+		mutex_lock(&ctrl->subsys->lock);
+		list_for_each_entry(tmp, &ctrl->subsys->ctrls, subsys_entry)
+			nvme_queue_scan(tmp);
+		mutex_unlock(&ctrl->subsys->lock);
+	}
+
 	/* Requeue if we have missed AENs */
 	if (test_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events))
 		nvme_queue_scan(ctrl);
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 9971045dbc05e..e73cc2e67ac51 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -329,6 +329,7 @@ enum nvme_ctrl_flags {
 	NVME_CTRL_SKIP_ID_CNS_CS	= 4,
 	NVME_CTRL_DIRTY_CAPABILITY	= 5,
 	NVME_CTRL_FROZEN		= 6,
+	NVME_CTRL_SCAN_REMOVED_NS	= 7,
 };
 
 struct nvme_ctrl {
-- 
2.47.3




More information about the Linux-nvme mailing list