On Wed, Sep 04, 2019 at 05:32:46PM +0200, Oleg Nesterov wrote:
> On 09/04, Frederic Weisbecker wrote:
> >
> > So what happens if, say:
> >
> >
> >            CPU 1                         CPU 2
> >    --------------------------------------------------------------
> >    rcu_read_lock()
> >    p = rcu_dereference(rq->task)
> >    if (refcount_inc_not_zero(p->rcu_users)) {
> >        .....
> >                                          release_task() {
> >                                              put_task_struct_rcu_user() {
> >                                                  call_rcu() {
> >                                                      queue rcu_head
> 
> in this particular case call_rcu() won't be called, so

Yeah I confused myself in finding the scenario but like you say below, 
release_task()
can simply happen between the p = rcu_dereference() and the refcount_inc to 
break things.

I thought the point of these rcu_users was to be able to do:

rcu_read_lock()
p = rcu_dereference(task)
if (!refcount_inc_not_zero(p->rcu_users)) {
    rcu_read_unlock();
    return -1;
}
rcu_read_unlock();

//do stuff with task

put_task_struct_rcu_user(p);

Thanks.

> 
> >                                                  }
> >                                              }
> >                                          }
> >        put_task_struct_rcu_user(); //here rcu_users has been overwritten
> 
> rcu_users won't be overwritten.
> 
> But nobody should try to increment ->rcu_users,
> 
>       rcu_read_lock();
>       p = rcu_dereference(rq->task);
>       refcount_inc_not_zero(p->rcu_users);
> 
> is already wrong because both release_task/last-schedule can happen in
> between, before refcount_inc_not_zero().
> 
> Oleg.
> 

Reply via email to