Re: [PATCH 2/3] task: RCU protect tasks on the runqueue

From: Peter Zijlstra
Date: Fri Sep 06 2019 - 03:07:54 EST


On Thu, Sep 05, 2019 at 03:02:49PM -0500, Eric W. Biederman wrote:
> Paul, what is the purpose of the barrier in rcu_assign_pointer?
>
> My intuition says it is the assignment half of rcu_dereference, and that
> anything that rcu_dereference does not need is too strong.

I see that Paul has also replied, but let me give another take on it.

RCU does *two* different but related things. It provide object
consistency and it provides object lifetime management.

Object consistency is provided by rcu_assign_pointer() /
rcu_dereference:

- rcu_assign_pointer() is a PUBLISH operation, it is meant to expose an
object to the world. In that respect it needs to ensure that all
previous stores to this object are complete before it writes the
pointer and exposes the object.

To this purpose, rcu_assign_pointer() is an smp_store_release().

- rcu_dereference() is a CONSUME operation. It matches the PUBLISH from
above and guarantees that any further loads/stores to the observed
object come after.

Naturally this would be an smp_load_acquire(), _HOWEVER_, since we need
the address of the object in order to construct a load/store from/to
said object, we can rely on the address-dependency to provide this
barrier (except for Alpha, which is fscking weird). After all if you
haven't completed the load of the (object) base address, you cannot
compute the object member address and issue any subsequent memops, now
can you ;-)

Now the thing here is that the 'rq->curr = next' assignment does _NOT_
expose the task (our object). The task is exposed the moment it enters
the PID hash. It is this that sets us free of the PUBLISH requirement
and thus we can use RCU_INIT_POINTER().


The object lifetime thing is provided by
rcu_read_load()/rcu_read_unlock() on the one hand and
synchronize_rcu()/call_rcu() on the other. That ensures that if you
observe an object inside the RCU read side section, the object storage
must stay valid.

And it is *that* properpy we wish to make use of.


Does this make sense to you?