Re: Why is there no list_prev_rcu()?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Dec 12, 2024 at 12:25:42AM +0100, Christian Brauner wrote:
> Hey Paul,
> 
> I have a rather dumb question...
> 
> I'm keeping a very boring:
> 
> static LIST_HEAD(mnt_ns_list);
> 
> of mount namespaces. Userspace can pass a file descriptor for a mount
> namespace in that list to the kernel and then open a file descriptor to
> the next or previous mount namespace.
> 
> As I was working on that I found list_next_rcu() but no
> list_prev_rcu(). Which made me curious and then I saw the comment in
> commit afa47fdfa29f ("rculist.h: Add list_tail_rcu()").
> 
> /**
>  * list_tail_rcu - returns the prev pointer of the head of the list
>  * @head: the head of the list
>  *
>  * Note: This should only be used with the list header, and even then
>  * only if list_del() and similar primitives are not also used on the
>  * list header.
>  */
> 
> That comment strongly suggests that list_prev_rcu() somehow isn't
> generally safe to do? Is that the case and if so why? And what are
> possible ways to safely get to the previous list entry under rcu?
> 
> (I'm currently doing this in an rbtree via rb_prev() and rb_next() but I
> can't do either of those locklessly which is why I want to keep a list
> in parallel as well.)

This is a design choice.  It would be easy to create an RCU-protected list
that allowed readers to iterate in both the ->next and ->prev directions.

Why the forward-only restriction?

Because most use cases only need to traverse forward.  Prohibiting
backwards traversal permits list_del_rcu() to poison the ->prev pointers,
which arguably makes for better error detection and debuggability.

If you need an RCU-protected bidirectional list, one way to supply
one would be to add list_del_bidir_rcu() and list_prev_bidir_rcu()
to the current list_head API, with the former dispensing with ->prev
poisoning and the latter adding rcu_dereference().  Note well that
p->lh.next->lh.prev will not necessarily be equal to p.  This is because
there might have been a concurrent insertion or deletion, which would
instead result in p->lh.next or p->lh.prev, respectively.

One alternative is to supply a different list_head structure that has
a full API.  But unless there is a strong reason for exploding the
API in the manner, adding the API members mentioned above seems like
it would be a better choice.

But in that case, there might need to be some sort of debugging features
prohibiting use of list_del_rcu() and list_prev_bidir_rcu() on the
same list.

Do you also need reverse-direction list iterators as well?

Details aside, it is eminently implementable.  How would you like to
proceed?

							Thanx, Paul




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux