rcu: Protect ->gp_flags accesses with ACCESS_ONCE()
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Tue, 18 Feb 2014 17:47:13 +0000 (09:47 -0800)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Tue, 29 Apr 2014 15:42:31 +0000 (08:42 -0700)
A number of ->gp_flags accesses don't have ACCESS_ONCE(), but all of
the can race against other loads or stores.  This commit therefore
applies ACCESS_ONCE() to the unprotected ->gp_flags accesses.

Reported-by: Alexey Roytman <alexey.roytman@oracle.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
kernel/rcu/tree.c

index 0c47e30..2c53ac9 100644 (file)
@@ -1403,12 +1403,12 @@ static int rcu_gp_init(struct rcu_state *rsp)
        rcu_bind_gp_kthread();
        raw_spin_lock_irq(&rnp->lock);
        smp_mb__after_unlock_lock();
-       if (rsp->gp_flags == 0) {
+       if (!ACCESS_ONCE(rsp->gp_flags)) {
                /* Spurious wakeup, tell caller to go back to sleep.  */
                raw_spin_unlock_irq(&rnp->lock);
                return 0;
        }
-       rsp->gp_flags = 0; /* Clear all flags: New grace period. */
+       ACCESS_ONCE(rsp->gp_flags) = 0; /* Clear all flags: New grace period. */
 
        if (WARN_ON_ONCE(rcu_gp_in_progress(rsp))) {
                /*
@@ -1501,7 +1501,7 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
        if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
                raw_spin_lock_irq(&rnp->lock);
                smp_mb__after_unlock_lock();
-               rsp->gp_flags &= ~RCU_GP_FLAG_FQS;
+               ACCESS_ONCE(rsp->gp_flags) &= ~RCU_GP_FLAG_FQS;
                raw_spin_unlock_irq(&rnp->lock);
        }
        return fqs_state;
@@ -1566,7 +1566,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
        rdp = this_cpu_ptr(rsp->rda);
        rcu_advance_cbs(rsp, rnp, rdp);  /* Reduce false positives below. */
        if (cpu_needs_another_gp(rsp, rdp)) {
-               rsp->gp_flags = RCU_GP_FLAG_INIT;
+               ACCESS_ONCE(rsp->gp_flags) = RCU_GP_FLAG_INIT;
                trace_rcu_grace_period(rsp->name,
                                       ACCESS_ONCE(rsp->gpnum),
                                       TPS("newreq"));
@@ -1695,7 +1695,7 @@ rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp,
                 */
                return;
        }
-       rsp->gp_flags = RCU_GP_FLAG_INIT;
+       ACCESS_ONCE(rsp->gp_flags) = RCU_GP_FLAG_INIT;
        trace_rcu_grace_period(rsp->name, ACCESS_ONCE(rsp->gpnum),
                               TPS("newreq"));
 
@@ -2320,7 +2320,7 @@ static void force_quiescent_state(struct rcu_state *rsp)
                raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
                return;  /* Someone beat us to it. */
        }
-       rsp->gp_flags |= RCU_GP_FLAG_FQS;
+       ACCESS_ONCE(rsp->gp_flags) |= RCU_GP_FLAG_FQS;
        raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
        wake_up(&rsp->gp_wq);  /* Memory barrier implied by wake_up() path. */
 }