* [PATCH v2 0/2] nvme: fix removing namespaces under SRCU readers
@ 2026-11-04 6:30 Qiliang Yuan
2026-11-04 6:30 ` [PATCH v2 1/2] srcu: Add list_splice_init_srcu() Qiliang Yuan
2026-11-04 6:30 ` [PATCH v2 2/2] nvme: wait for SRCU readers before splicing the namespace list Qiliang Yuan
0 siblings, 2 replies; 3+ messages in thread
From: Qiliang Yuan @ 2026-11-04 6:30 UTC (permalink / raw)
To: Keith Busch, Jens Axboe, Christoph Hellwig, Sagi Grimberg,
Lai Jiangshan, Paul E. McKenney, Josh Triplett, Onur Özkan,
Steven Rostedt, Mathieu Desnoyers
Cc: linux-nvme, linux-kernel, rcu, Qiliang Yuan, stable
nvme_remove_namespaces() splices the namespace list with
list_splice_init_rcu() and synchronize_rcu(), but the list is read
under SRCU. A reader still on the last namespace can then walk onto the
on-stack list head, which KASAN reports as a stack-out-of-bounds read.
Patch 1 adds list_splice_init_srcu() for lists read under SRCU, and
patch 2 uses it in nvme. Both are needed for the fix.
Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
---
V1 -> V2:
- Add list_splice_init_srcu() instead of open-coding the splice in nvme
- Put it in srcu.h, as rculist.h doesn't include srcu.h
- Update the numbers from a new run, median of 3 runs per boot
v1: https://lore.kernel.org/r/20261103-bug-nvme-remove-ns-srcu-v1-1-e239087d63ac@gmail.com
---
Qiliang Yuan (2):
srcu: Add list_splice_init_srcu()
nvme: wait for SRCU readers before splicing the namespace list
drivers/nvme/host/core.c | 3 +--
include/linux/srcu.h | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+), 2 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261102-bug-nvme-remove-ns-srcu-93d8a75a9b1b
Best regards,
--
Qiliang Yuan <odys.yuan@gmail.com>
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v2 1/2] srcu: Add list_splice_init_srcu()
2026-11-04 6:30 [PATCH v2 0/2] nvme: fix removing namespaces under SRCU readers Qiliang Yuan
@ 2026-11-04 6:30 ` Qiliang Yuan
2026-11-04 6:30 ` [PATCH v2 2/2] nvme: wait for SRCU readers before splicing the namespace list Qiliang Yuan
1 sibling, 0 replies; 3+ messages in thread
From: Qiliang Yuan @ 2026-11-04 6:30 UTC (permalink / raw)
To: Keith Busch, Jens Axboe, Christoph Hellwig, Sagi Grimberg,
Lai Jiangshan, Paul E. McKenney, Josh Triplett, Onur Özkan,
Steven Rostedt, Mathieu Desnoyers
Cc: linux-nvme, linux-kernel, rcu, Qiliang Yuan, stable
list_splice_init_rcu() makes a list look empty to new readers, waits for
the current ones with the given sync function, and only then links the
entries into the new list. The sync function takes no argument, so it
can wait for RCU readers but not for the readers of an srcu_struct.
Passing synchronize_rcu() for a list read under SRCU still builds, but
leaves SRCU readers on the entries while the last one's next pointer is
moved onto the new list head. nvme_remove_namespaces() does this today.
Add list_splice_init_srcu(), which waits for the readers of the given
srcu_struct instead.
Cc: stable@vger.kernel.org
Suggested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
---
include/linux/srcu.h | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
index 1a8a465a5650d..d4dcaeb83e2b6 100644
--- a/include/linux/srcu.h
+++ b/include/linux/srcu.h
@@ -18,6 +18,7 @@
#include <linux/mutex.h>
#include <linux/rcupdate.h>
+#include <linux/rculist.h>
#include <linux/workqueue.h>
#include <linux/rcu_segcblist.h>
@@ -118,6 +119,41 @@ void cleanup_srcu_struct(struct srcu_struct *ssp);
void synchronize_srcu(struct srcu_struct *ssp);
void synchronize_srcu_atomic(struct srcu_struct *ssp);
+/**
+ * list_splice_init_srcu - splice an SRCU-protected list into an existing list
+ * @list: the SRCU-protected list to splice
+ * @head: the place in the existing list to splice the first list into
+ * @ssp: the srcu_struct that readers of @list use
+ *
+ * Like list_splice_init_rcu(), but wait for the SRCU readers of @list
+ * instead of RCU ones, so that none of them can follow a next pointer
+ * onto @head.
+ *
+ * Note that this function blocks, and that the caller must prevent any
+ * other updates to @list.
+ */
+static inline void list_splice_init_srcu(struct list_head *list,
+ struct list_head *head,
+ struct srcu_struct *ssp)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *next = head->next;
+
+ if (list_empty(list))
+ return;
+
+ INIT_LIST_HEAD_RCU(list);
+ synchronize_srcu(ssp);
+ ASSERT_EXCLUSIVE_ACCESS(*first);
+ ASSERT_EXCLUSIVE_ACCESS(*last);
+
+ last->next = next;
+ rcu_assign_pointer(list_next_rcu(head), first);
+ first->prev = head;
+ next->prev = last;
+}
+
#define SRCU_GET_STATE_COMPLETED 0x1
/**
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v2 2/2] nvme: wait for SRCU readers before splicing the namespace list
2026-11-04 6:30 [PATCH v2 0/2] nvme: fix removing namespaces under SRCU readers Qiliang Yuan
2026-11-04 6:30 ` [PATCH v2 1/2] srcu: Add list_splice_init_srcu() Qiliang Yuan
@ 2026-11-04 6:30 ` Qiliang Yuan
1 sibling, 0 replies; 3+ messages in thread
From: Qiliang Yuan @ 2026-11-04 6:30 UTC (permalink / raw)
To: Keith Busch, Jens Axboe, Christoph Hellwig, Sagi Grimberg,
Lai Jiangshan, Paul E. McKenney, Josh Triplett, Onur Özkan,
Steven Rostedt, Mathieu Desnoyers
Cc: linux-nvme, linux-kernel, rcu, Qiliang Yuan, stable
Readers walk ctrl->namespaces under ctrl->srcu, and some of them sleep
there, e.g. nvme_wait_freeze() waiting for I/O to drain.
nvme_remove_namespaces() moves the list onto its on-stack ns_list with
list_splice_init_rcu(), which only waits for RCU readers before
relinking the entries. A reader still on the last namespace then follows
its next pointer to ns_list instead of ctrl->namespaces and treats the
stack as a namespace. Deleting a controller while a Format NVM
passthrough waits for a delayed read on the last namespace gives:
BUG: KASAN: stack-out-of-bounds in nvme_wait_freeze+0x102/0x120
Read of size 8 at addr ff110001d2f3fc38 by task nvme/4413
Call Trace:
nvme_wait_freeze
nvme_passthru_start
nvme_submit_user_cmd
nvme_user_cmd
nvme_dev_ioctl
BUG: unable to handle page fault for address: ffffffff8af04850
Use list_splice_init_srcu() instead, which waits for the SRCU readers.
This also takes the RCU grace period out of every controller deletion.
Deleting 64 tcp controllers with one namespace each, median of 3 runs on
each of two boots per kernel:
before after
nvme disconnect-all (ms) 3491 / 3509 2996 / 3165
nvme_remove_namespaces() avg (ms) 39.0 / 40.5 31.9 / 34.7
Fixes: be647e2c76b2 ("nvme: use srcu for iterating namespace list")
Cc: stable@vger.kernel.org
Signed-off-by: Qiliang Yuan <odys.yuan@gmail.com>
---
drivers/nvme/host/core.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index a7a4d09644c13..cdb576db23809 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -4755,9 +4755,8 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
nvme_change_ctrl_state(ctrl, NVME_CTRL_DELETING_NOIO);
mutex_lock(&ctrl->namespaces_lock);
- list_splice_init_rcu(&ctrl->namespaces, &ns_list, synchronize_rcu);
+ list_splice_init_srcu(&ctrl->namespaces, &ns_list, &ctrl->srcu);
mutex_unlock(&ctrl->namespaces_lock);
- synchronize_srcu(&ctrl->srcu);
list_for_each_entry_safe(ns, next, &ns_list, list)
nvme_ns_remove(ns);
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-04 6:31 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-04 6:30 [PATCH v2 0/2] nvme: fix removing namespaces under SRCU readers Qiliang Yuan
2026-11-04 6:30 ` [PATCH v2 1/2] srcu: Add list_splice_init_srcu() Qiliang Yuan
2026-11-04 6:30 ` [PATCH v2 2/2] nvme: wait for SRCU readers before splicing the namespace list Qiliang Yuan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®