Skip to content

Commit 2caebef

Browse files
committed
rcu: Move rcu_dynticks_eqs_online() to rcu_cpu_starting()
The purpose of rcu_dynticks_eqs_online() is to adjust the ->dynticks counter of an incoming CPU when required. It is currently invoked from rcutree_prepare_cpu(), which runs before the incoming CPU is running, and thus on some other CPU. This makes the per-CPU accesses in rcu_dynticks_eqs_online() iffy at best, and it all "works" only because the running CPU cannot possibly be in dyntick-idle mode, which means that rcu_dynticks_eqs_online() never has any effect. It is currently OK for rcu_dynticks_eqs_online() to have no effect, but only because the CPU-offline process just happens to leave ->dynticks in the correct state. After all, if ->dynticks were in the wrong state on a just-onlined CPU, rcutorture would complain bitterly the next time that CPU went idle, at least in kernels built with CONFIG_RCU_EQS_DEBUG=y, for example, those built by rcutorture scenario TREE04. One could argue that this means that rcu_dynticks_eqs_online() is unnecessary, however, removing it would make the CPU-online process vulnerable to slight changes in the CPU-offline process. One could also ask why it is safe to move the rcu_dynticks_eqs_online() call so late in the CPU-online process. Indeed, there was a time when it would not have been safe, which does much to explain its current location. However, the marking of a CPU as online from an RCU perspective has long since moved from rcutree_prepare_cpu() to rcu_cpu_starting(), and all that is required is that ->dynticks be set correctly by the time that the CPU is marked as online from an RCU perspective. After all, the RCU grace-period kthread does not check to see if offline CPUs are also idle. (In case you were curious, this is one reason why there is quiescent-state reporting as part of the offlining process.) This commit therefore moves the call to rcu_dynticks_eqs_online() from rcutree_prepare_cpu() to rcu_cpu_starting(), this latter being guaranteed to be running on the incoming CPU. The call to this function must of course be placed before this rcu_cpu_starting() announces this CPU's presence to RCU. Reported-by: Mathieu Desnoyers <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent ebc88ad commit 2caebef

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

kernel/rcu/tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4129,7 +4129,6 @@ int rcutree_prepare_cpu(unsigned int cpu)
41294129
rdp->n_force_qs_snap = READ_ONCE(rcu_state.n_force_qs);
41304130
rdp->blimit = blimit;
41314131
rdp->dynticks_nesting = 1; /* CPU not up, no tearing. */
4132-
rcu_dynticks_eqs_online();
41334132
raw_spin_unlock_rcu_node(rnp); /* irqs remain disabled. */
41344133

41354134
/*
@@ -4249,6 +4248,7 @@ void rcu_cpu_starting(unsigned int cpu)
42494248
mask = rdp->grpmask;
42504249
WRITE_ONCE(rnp->ofl_seq, rnp->ofl_seq + 1);
42514250
WARN_ON_ONCE(!(rnp->ofl_seq & 0x1));
4251+
rcu_dynticks_eqs_online();
42524252
smp_mb(); // Pair with rcu_gp_cleanup()'s ->ofl_seq barrier().
42534253
raw_spin_lock_irqsave_rcu_node(rnp, flags);
42544254
WRITE_ONCE(rnp->qsmaskinitnext, rnp->qsmaskinitnext | mask);

0 commit comments

Comments
 (0)