On Mon, Jun 03, 2019 at 10:46:40AM +0800, Herbert Xu wrote:

> The case we were discussing is from net/ipv4/inet_fragment.c from
> the net-next tree:

BTW, thank you for keeping me and other people who intervened in that
discussion in Cc:...

  Andrea


> 
> void fqdir_exit(struct fqdir *fqdir)
> {
>       ...
>       fqdir->dead = true;
> 
>       /* call_rcu is supposed to provide memory barrier semantics,
>        * separating the setting of fqdir->dead with the destruction
>        * work.  This implicit barrier is paired with inet_frag_kill().
>        */
> 
>       INIT_RCU_WORK(&fqdir->destroy_rwork, fqdir_rwork_fn);
>       queue_rcu_work(system_wq, &fqdir->destroy_rwork);
> }
> 
> and
> 
> void inet_frag_kill(struct inet_frag_queue *fq)
> {
>               ...
>               rcu_read_lock();
>               /* The RCU read lock provides a memory barrier
>                * guaranteeing that if fqdir->dead is false then
>                * the hash table destruction will not start until
>                * after we unlock.  Paired with inet_frags_exit_net().
>                */
>               if (!fqdir->dead) {
>                       rhashtable_remove_fast(&fqdir->rhashtable, &fq->node,
>                                              fqdir->f->rhash_params);
>                       ...
>               }
>               ...
>               rcu_read_unlock();
>               ...
> }
> 
> I simplified this to
> 
> Initial values:
> 
> a = 0
> b = 0
> 
> CPU1                          CPU2
> ----                          ----
> a = 1                         rcu_read_lock
> synchronize_rcu                       if (a == 0)
> b = 2                                 b = 1
>                               rcu_read_unlock
> 
> On exit we want this to be true:
> b == 2

Reply via email to