Re: Why is there no list_prev_rcu()?

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

 



On Wed, Dec 11, 2024 at 03:44:34PM -0800, Paul E. McKenney wrote:
> 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.

Aha, thank you for the explanation!

> 
> 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.

Yes, I agree.

> 
> 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?

No, I don't think so. I just need the ability to walk somewhere from the
middle but not the whole list from the end to the beginning... yet... I
don't want to make promises I can't keep. :)

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

I will try and add list_del_bidir_rcu() and list_prev_bidir_rcu().
I'll Cc you on the series.

Thank you, 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