Re: [PATCH RT] locking: Make spinlock_t and rwlock_t a RCU section on RT

From: Paul E. McKenney
Date: Fri Nov 29 2019 - 17:51:52 EST


On Fri, Nov 29, 2019 at 04:45:35PM +0100, Sebastian Andrzej Siewior wrote:
> On 2019-11-25 12:25:45 [-0500], Steven Rostedt wrote:
> > On Fri, 22 Nov 2019 19:01:40 +0100
> > Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> wrote:
> >
> > > Let me give you an example how I got into this:
> > >
> > > do_sigaction() acquires p->sighand->siglock and then iterates over list
> > > via for_each_thread() which is a list_for_each_entry_rcu(). No RCU lock
> > > is held, just the siglock.
> > > On removal side, __unhash_process() removes a task from the list but
> > > while doing so it holds the siglock and tasklist_lock. So it is
> > > perfectly fine.
> > > Later, we have:
> > > |do_exit()
> > > | -> exit_notify()
> > > | -> write_lock_irq(&tasklist_lock);
> > > | -> forget_original_parent()
> > > | -> find_child_reaper()
> > > | -> find_alive_thread()
> > > | -> for_each_thread()
> > >
> > > find_alive_thread() does the for_each_thread() and checks PF_EXITING.
> > > it might be enough for not operating on "removed" task_struct. It
> > > dereferences task_struct->flags while looking for PF_EXITING. At this
> > > point only tasklist_lock is acquired.
> > > I have *no* idea if the whole synchronisation based on siglock/
> > > PF_EXITING/ tasklist_lock is enough and RCU simply doesn't matter. It
> > > seems so.
> > >
> > > I am a little worried if this construct here (or somewhere else) assumes
> > > that holding one of those locks, which disable preemption, is the same
> > > as rcu_read_lock() (or rcu_read_lock_sched()).
> >
> > I'm wondering if instead, we should start throwing in rcu_read_lock()
> > and explicitly have the preempt disabled rcu use that as well, since
> > today it's basically one and the same.
>
> Any comment from the RCU camp on this?
> Maybe just adding the missing RCU annotation for the list annotation is
> enough (like if lock X or Y is held then everything fine). !RT gets this
> implicit via preempt_disable(). I'm just worried if someone expects
> this kind of behaviour.
> If I remember correctly, Scott added rcu_read_lock() recently to
> local_bh_disable() because RCU-torture expected it.

Adding an explicit rcu_read_lock()/rcu_read_unlock() pair to the various
spinlock primitives for -rt seems quite sensible to me. My guess is
that non-rt CONFIG_PREEMPT=y uses in mainline might not like the extra
overhead.

For the trylock primitives, would it make more sense to do the
rcu_read_lock() only after successful acquisition, or to do the
rcu_read_lock() to begin with and then do rcu_read_unlock() upon failure?
I would guess the latter, but don't feel strongly about it.

Thanx, Paul