[PATCH v2 1/2] srcu: Add list_splice_init_srcu()
Paul E. McKenney
paulmck at kernel.org
Wed Nov 4 09:14:12 PST 2026
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().
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