[PATCH v2 1/2] srcu: Add list_splice_init_srcu()
Paul E. McKenney
paulmck at kernel.org
Wed Nov 4 17:46:45 PST 2026
On Wed, Nov 04, 2026 at 09:14:13AM -0800, Paul E. McKenney wrote:
> On Wed, Nov 04, 2026 at 01:30:39AM -0500, Qiliang Yuan wrote:
> > 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 at vger.kernel.org
> > Suggested-by: Christoph Hellwig <hch at lst.de>
> > Signed-off-by: Qiliang Yuan <odys.yuan at gmail.com>
>
> I am not inalterably opposed to adding a list_splice_init_srcu(),
> especially if quite a few more users show up, but here is what I was
> expecting people to do:
>
> static void synchronize_my_srcu(void)
> {
> synchronize_srcu(&my_srcu);
> }
>
> ...
>
> list_splice_init_rcu(l, h, synchronize_my_srcu);
>
> We need at least six uses of the above idiom to break even on the line
> of code required for introducing a list_splice_init_srcu().
Given Qiliang's response:
Reviewed-by: Paul E. McKenney <paulmck at kernel.org>
Thanx, Paul
> > ---
> > 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
> >
More information about the Linux-nvme
mailing list