summaryrefslogtreecommitdiff
path: root/Documentation/RCU
diff options
context:
space:
mode:
authorJoel Fernandes <joelagnelf@nvidia.com>2025-07-15 16:01:53 -0400
committerNeeraj Upadhyay <neeraj.iitr10@gmail.com>2025-07-22 17:09:35 +0530
commit30a7806adab5f6b971cf07439ed6a3fac3fd80cf (patch)
tree979c6b33a947fc86469cab48b22c93ccca2bdb0e /Documentation/RCU
parent908a97eba8c8b510996bf5d77d1e3070d59caa6d (diff)
downloadlinux-30a7806adab5f6b971cf07439ed6a3fac3fd80cf.tar.gz
linux-30a7806adab5f6b971cf07439ed6a3fac3fd80cf.tar.bz2
linux-30a7806adab5f6b971cf07439ed6a3fac3fd80cf.zip
rcu: Document GP init vs hotplug-scan ordering requirements
Add detailed comments explaining the critical ordering constraints during RCU grace period initialization, based on discussions with Frederic. Reviewed-by: "Paul E. McKenney" <paulmck@kernel.org> Co-developed-by: Frederic Weisbecker <frederic@kernel.org> Signed-off-by: Frederic Weisbecker <frederic@kernel.org> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> Signed-off-by: Neeraj Upadhyay (AMD) <neeraj.upadhyay@kernel.org>
Diffstat (limited to 'Documentation/RCU')
-rw-r--r--Documentation/RCU/Design/Requirements/Requirements.rst41
1 files changed, 41 insertions, 0 deletions
diff --git a/Documentation/RCU/Design/Requirements/Requirements.rst b/Documentation/RCU/Design/Requirements/Requirements.rst
index 6125e7068d2c..771a1ce4c84d 100644
--- a/Documentation/RCU/Design/Requirements/Requirements.rst
+++ b/Documentation/RCU/Design/Requirements/Requirements.rst
@@ -1970,6 +1970,47 @@ corresponding CPU's leaf node lock is held. This avoids race conditions
between RCU's hotplug notifier hooks, the grace period initialization
code, and the FQS loop, all of which refer to or modify this bookkeeping.
+Note that grace period initialization (rcu_gp_init()) must carefully sequence
+CPU hotplug scanning with grace period state changes. For example, the
+following race could occur in rcu_gp_init() if rcu_seq_start() were to happen
+after the CPU hotplug scanning.
+
+.. code-block:: none
+
+ CPU0 (rcu_gp_init) CPU1 CPU2
+ --------------------- ---- ----
+ // Hotplug scan first (WRONG ORDER)
+ rcu_for_each_leaf_node(rnp) {
+ rnp->qsmaskinit = rnp->qsmaskinitnext;
+ }
+ rcutree_report_cpu_starting()
+ rnp->qsmaskinitnext |= mask;
+ rcu_read_lock()
+ r0 = *X;
+ r1 = *X;
+ X = NULL;
+ cookie = get_state_synchronize_rcu();
+ // cookie = 8 (future GP)
+ rcu_seq_start(&rcu_state.gp_seq);
+ // gp_seq = 5
+
+ // CPU1 now invisible to this GP!
+ rcu_for_each_node_breadth_first() {
+ rnp->qsmask = rnp->qsmaskinit;
+ // CPU1 not included!
+ }
+
+ // GP completes without CPU1
+ rcu_seq_end(&rcu_state.gp_seq);
+ // gp_seq = 8
+ poll_state_synchronize_rcu(cookie);
+ // Returns true!
+ kfree(r1);
+ r2 = *r0; // USE-AFTER-FREE!
+
+By incrementing gp_seq first, CPU1's RCU read-side critical section
+is guaranteed to not be missed by CPU2.
+
Scheduler and RCU
~~~~~~~~~~~~~~~~~