OSDN Git Service

srcu: Fix __call_srcu()/srcu_get_delay() datarace
authorPaul E. McKenney <paulmck@kernel.org>
Mon, 23 Dec 2019 03:36:33 +0000 (19:36 -0800)
committerPaul E. McKenney <paulmck@kernel.org>
Fri, 21 Feb 2020 00:01:11 +0000 (16:01 -0800)
The srcu_struct structure's ->srcu_gp_seq_needed_exp field is accessed
locklessly, so updates must use WRITE_ONCE().  This commit therefore
adds the needed WRITE_ONCE() invocations.

This data race was reported by KCSAN.  Not appropriate for backporting
due to failure being unlikely.

Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
kernel/rcu/srcutree.c

index b1edac9..79848f7 100644 (file)
@@ -534,7 +534,7 @@ static void srcu_gp_end(struct srcu_struct *ssp)
        rcu_seq_end(&ssp->srcu_gp_seq);
        gpseq = rcu_seq_current(&ssp->srcu_gp_seq);
        if (ULONG_CMP_LT(ssp->srcu_gp_seq_needed_exp, gpseq))
-               ssp->srcu_gp_seq_needed_exp = gpseq;
+               WRITE_ONCE(ssp->srcu_gp_seq_needed_exp, gpseq);
        spin_unlock_irq_rcu_node(ssp);
        mutex_unlock(&ssp->srcu_gp_mutex);
        /* A new grace period can start at this point.  But only one. */
@@ -614,7 +614,7 @@ static void srcu_funnel_exp_start(struct srcu_struct *ssp, struct srcu_node *snp
        }
        spin_lock_irqsave_rcu_node(ssp, flags);
        if (ULONG_CMP_LT(ssp->srcu_gp_seq_needed_exp, s))
-               ssp->srcu_gp_seq_needed_exp = s;
+               WRITE_ONCE(ssp->srcu_gp_seq_needed_exp, s);
        spin_unlock_irqrestore_rcu_node(ssp, flags);
 }
 
@@ -674,7 +674,7 @@ static void srcu_funnel_gp_start(struct srcu_struct *ssp, struct srcu_data *sdp,
                smp_store_release(&ssp->srcu_gp_seq_needed, s); /*^^^*/
        }
        if (!do_norm && ULONG_CMP_LT(ssp->srcu_gp_seq_needed_exp, s))
-               ssp->srcu_gp_seq_needed_exp = s;
+               WRITE_ONCE(ssp->srcu_gp_seq_needed_exp, s);
 
        /* If grace period not already done and none in progress, start it. */
        if (!rcu_seq_done(&ssp->srcu_gp_seq, s) &&