Skip to content

Commit 4bc6b74

Browse files
Neeraj Upadhyaypaulmckrcu
authored andcommitted
rcu: Allow only one expedited GP to run concurrently with wakeups
The current expedited RCU grace-period code expects that a task requesting an expedited grace period cannot awaken until that grace period has reached the wakeup phase. However, it is possible for a long preemption to result in the waiting task never sleeping. For example, consider the following sequence of events: 1. Task A starts an expedited grace period by invoking synchronize_rcu_expedited(). It proceeds normally up to the wait_event() near the end of that function, and is then preempted (or interrupted or whatever). 2. The expedited grace period completes, and a kworker task starts the awaken phase, having incremented the counter and acquired the rcu_state structure's .exp_wake_mutex. This kworker task is then preempted or interrupted or whatever. 3. Task A resumes and enters wait_event(), which notes that the expedited grace period has completed, and thus doesn't sleep. 4. Task B starts an expedited grace period exactly as did Task A, complete with the preemption (or whatever delay) just before the call to wait_event(). 5. The expedited grace period completes, and another kworker task starts the awaken phase, having incremented the counter. However, it blocks when attempting to acquire the rcu_state structure's .exp_wake_mutex because step 2's kworker task has not yet released it. 6. Steps 4 and 5 repeat, resulting in overflow of the rcu_node structure's ->exp_wq[] array. In theory, this is harmless. Tasks waiting on the various ->exp_wq[] array will just be spuriously awakened, but they will just sleep again on noting that the rcu_state structure's ->expedited_sequence value has not advanced far enough. In practice, this wastes CPU time and is an accident waiting to happen. This commit therefore moves the rcu_exp_gp_seq_end() call that officially ends the expedited grace period (along with associate tracing) until after the ->exp_wake_mutex has been acquired. This prevents Task A from awakening prematurely, thus preventing more than one expedited grace period from being in flight during a previous expedited grace period's wakeup phase. Fixes: 3b5f668 ("rcu: Overlap wakeups with next expedited grace period") Signed-off-by: Neeraj Upadhyay <[email protected]> [ paulmck: Added updated comment. ] Signed-off-by: Paul E. McKenney <[email protected]>
1 parent fd6bc19 commit 4bc6b74

File tree

1 file changed

+5
-6
lines changed

1 file changed

+5
-6
lines changed

kernel/rcu/tree_exp.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -539,14 +539,13 @@ static void rcu_exp_wait_wake(unsigned long s)
539539
struct rcu_node *rnp;
540540

541541
synchronize_sched_expedited_wait();
542-
rcu_exp_gp_seq_end();
543-
trace_rcu_exp_grace_period(rcu_state.name, s, TPS("end"));
544542

545-
/*
546-
* Switch over to wakeup mode, allowing the next GP, but -only- the
547-
* next GP, to proceed.
548-
*/
543+
// Switch over to wakeup mode, allowing the next GP to proceed.
544+
// End the previous grace period only after acquiring the mutex
545+
// to ensure that only one GP runs concurrently with wakeups.
549546
mutex_lock(&rcu_state.exp_wake_mutex);
547+
rcu_exp_gp_seq_end();
548+
trace_rcu_exp_grace_period(rcu_state.name, s, TPS("end"));
550549

551550
rcu_for_each_node_breadth_first(rnp) {
552551
if (ULONG_CMP_LT(READ_ONCE(rnp->exp_seq_rq), s)) {

0 commit comments

Comments
 (0)