rcu: Attempt QS when CPU discovers GP for strict GPs
authorPaul E. McKenney <paulmck@kernel.org>
Thu, 6 Aug 2020 23:35:08 +0000 (16:35 -0700)
committerPaul E. McKenney <paulmck@kernel.org>
Tue, 25 Aug 2020 01:40:26 +0000 (18:40 -0700)
A given CPU normally notes a new grace period during one RCU_SOFTIRQ,
but avoids reporting the corresponding quiescent state until some later
RCU_SOFTIRQ.  This leisurly approach improves efficiency by increasing
the number of update requests served by each grace period, but is not
what is needed for kernels built with CONFIG_RCU_STRICT_GRACE_PERIOD=y.

This commit therefore adds a new rcu_strict_gp_check_qs() function
which, in CONFIG_RCU_STRICT_GRACE_PERIOD=y kernels, simply enters and
immediately exist an RCU read-side critical section.  If the CPU is
in a quiescent state, the rcu_read_unlock() will attempt to report an
immediate quiescent state.  This rcu_strict_gp_check_qs() function is
invoked from note_gp_changes(), so that a CPU just noticing a new grace
period might immediately report a quiescent state for that grace period.

Reported-by Jann Horn <jannh@google.com>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
kernel/rcu/tree.c

index 443685704f5eaa2d845e9c5631f37fdd6472c5e5..36a860c4648bd120b59f39572b76e3a875beb23c 100644 (file)
@@ -1574,6 +1574,19 @@ static void __maybe_unused rcu_advance_cbs_nowake(struct rcu_node *rnp,
        raw_spin_unlock_rcu_node(rnp);
 }
 
+/*
+ * In CONFIG_RCU_STRICT_GRACE_PERIOD=y kernels, attempt to generate a
+ * quiescent state.  This is intended to be invoked when the CPU notices
+ * a new grace period.
+ */
+static void rcu_strict_gp_check_qs(void)
+{
+       if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD)) {
+               rcu_read_lock();
+               rcu_read_unlock();
+       }
+}
+
 /*
  * Update CPU-local rcu_data state to record the beginnings and ends of
  * grace periods.  The caller must hold the ->lock of the leaf rcu_node
@@ -1644,6 +1657,7 @@ static void note_gp_changes(struct rcu_data *rdp)
        }
        needwake = __note_gp_changes(rnp, rdp);
        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
+       rcu_strict_gp_check_qs();
        if (needwake)
                rcu_gp_kthread_wake();
 }