rcu: Mark rcu_state.gp_seq to detect concurrent writes
authorPaul E. McKenney <paulmck@kernel.org>
Mon, 10 Feb 2020 17:58:37 +0000 (09:58 -0800)
committerPaul E. McKenney <paulmck@kernel.org>
Sat, 21 Mar 2020 23:13:39 +0000 (16:13 -0700)
The rcu_state structure's gp_seq field is only to be modified by the RCU
grace-period kthread, which is single-threaded.  This commit therefore
enlists KCSAN's help in enforcing this restriction.

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

index 6c62481..739788f 100644 (file)
@@ -1209,7 +1209,7 @@ static bool rcu_start_this_gp(struct rcu_node *rnp_start, struct rcu_data *rdp,
                trace_rcu_this_gp(rnp, rdp, gp_seq_req, TPS("NoGPkthread"));
                goto unlock_out;
        }
-       trace_rcu_grace_period(rcu_state.name, READ_ONCE(rcu_state.gp_seq), TPS("newreq"));
+       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq, TPS("newreq"));
        ret = true;  /* Caller must wake GP kthread. */
 unlock_out:
        /* Push furthest requested GP to leaf node and rcu_data structure. */
@@ -1657,8 +1657,7 @@ static void rcu_gp_fqs_loop(void)
                        WRITE_ONCE(rcu_state.jiffies_kick_kthreads,
                                   jiffies + (j ? 3 * j : 2));
                }
-               trace_rcu_grace_period(rcu_state.name,
-                                      READ_ONCE(rcu_state.gp_seq),
+               trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                       TPS("fqswait"));
                rcu_state.gp_state = RCU_GP_WAIT_FQS;
                ret = swait_event_idle_timeout_exclusive(
@@ -1672,13 +1671,11 @@ static void rcu_gp_fqs_loop(void)
                /* If time for quiescent-state forcing, do it. */
                if (ULONG_CMP_GE(jiffies, rcu_state.jiffies_force_qs) ||
                    (gf & RCU_GP_FLAG_FQS)) {
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("fqsstart"));
                        rcu_gp_fqs(first_gp_fqs);
                        first_gp_fqs = false;
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("fqsend"));
                        cond_resched_tasks_rcu_qs();
                        WRITE_ONCE(rcu_state.gp_activity, jiffies);
@@ -1689,8 +1686,7 @@ static void rcu_gp_fqs_loop(void)
                        cond_resched_tasks_rcu_qs();
                        WRITE_ONCE(rcu_state.gp_activity, jiffies);
                        WARN_ON(signal_pending(current));
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("fqswaitsig"));
                        ret = 1; /* Keep old FQS timing. */
                        j = jiffies;
@@ -1782,7 +1778,7 @@ static void rcu_gp_cleanup(void)
                WRITE_ONCE(rcu_state.gp_flags, RCU_GP_FLAG_INIT);
                WRITE_ONCE(rcu_state.gp_req_activity, jiffies);
                trace_rcu_grace_period(rcu_state.name,
-                                      READ_ONCE(rcu_state.gp_seq),
+                                      rcu_state.gp_seq,
                                       TPS("newreq"));
        } else {
                WRITE_ONCE(rcu_state.gp_flags,
@@ -1801,8 +1797,7 @@ static int __noreturn rcu_gp_kthread(void *unused)
 
                /* Handle grace-period start. */
                for (;;) {
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("reqwait"));
                        rcu_state.gp_state = RCU_GP_WAIT_GPS;
                        swait_event_idle_exclusive(rcu_state.gp_wq,
@@ -1815,8 +1810,7 @@ static int __noreturn rcu_gp_kthread(void *unused)
                        cond_resched_tasks_rcu_qs();
                        WRITE_ONCE(rcu_state.gp_activity, jiffies);
                        WARN_ON(signal_pending(current));
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("reqwaitsig"));
                }