[PATCH v3 1/2] nvme-multipath: apply delayed_removal_secs changes to a pending removal

From: Qiliang Yuan

Date: Sat Nov 14 2026 - 21:16:06 EST


With delayed_removal_secs set, removing the last path of a namespace
head doesn't delete the head right away. nvme_mpath_remove_disk()
queues remove_work with the configured delay, and bios submitted in the
meantime wait on head->requeue_list in case a path comes back.

A write to delayed_removal_secs only takes effect for removals that
start later. A removal that is already pending keeps the old delay, so
clearing the attribute leaves the queued bios waiting until that delay
expires instead of failing them, and lowering or raising it doesn't
move the pending removal either.

Requeue a pending remove_work with the new delay when the attribute is
written. Cancel it first so that the module reference taken for it
carries over, as nvme_init_ns_head() does when a path comes back.

With delayed_removal_secs set and no path left, the attribute is
changed two seconds later and the head is removed after (mean of two
runs, min-max in parentheses):

delay (s) before (ms) after (ms) change
30 -> 0 26510 (26053-26967) 8 (8-8) -99.97%
30 -> 5 27994 (27457-28531) 6194 (5589-6798) -78%
10 -> 30 8131 (8086-8176) 29802 (29522-30082) +267%

A direct read queued before the 30 -> 0 write fails after:

before (ms) after (ms) change
26466 (26017-26915) 4 (4-4) -99.98%

Fixes: 62188639ec160 ("nvme-multipath: introduce delayed removal of the multipath head node")
Suggested-by: Nilay Shroff <nilay@xxxxxxxxxxxxx>
Signed-off-by: Qiliang Yuan <qiliang.yuan@xxxxxxxxx>
---
drivers/nvme/host/multipath.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index ae8059366b57d..35278b9c4de60 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -1242,6 +1242,9 @@ static ssize_t delayed_removal_secs_store(struct device *dev,
mutex_lock(&head->subsys->lock);
head->delayed_removal_secs = sec;
assign_bit(NVME_NSHEAD_QUEUE_IF_NO_PATH, &head->flags, sec);
+ /* Apply the new delay to a removal that is already pending */
+ if (cancel_delayed_work(&head->remove_work))
+ queue_delayed_work(nvme_wq, &head->remove_work, sec * HZ);
mutex_unlock(&head->subsys->lock);
/*
* Ensure that update to NVME_NSHEAD_QUEUE_IF_NO_PATH is seen

--
2.43.0