Re: rcu_read_lock lost its compiler barrier

From: Andrea Parri
Date: Thu Jun 06 2019 - 04:43:11 EST


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