Skip to content

Commit f2e555f

Browse files
Frederic WeisbeckerNeeraj Upadhyay (AMD)
authored andcommitted
rcu/exp: Protect against early QS report
When a grace period is started, the ->expmask of each node is set up from sync_exp_reset_tree(). Then later on each leaf node also initialize its ->exp_tasks pointer. This means that the initialization of the quiescent state of a node and the initialization of its blocking tasks happen with an unlocked node gap in-between. It happens to be fine because nothing is expected to report an exp quiescent state within this gap, since no IPI have been issued yet and every rdp's ->cpu_no_qs.b.exp should be false. However if it were to happen by accident, the quiescent state could be reported and propagated while ignoring tasks that blocked _before_ the start of the grace period. Prevent such trouble to happen in the future and initialize both the quiescent states mask to report and the blocked tasks head from the same node locked block. If a task blocks within an RCU read side critical section before sync_exp_reset_tree() is called and is then unblocked between sync_exp_reset_tree() and __sync_rcu_exp_select_node_cpus(), the QS won't be reported because no RCU exp IPI had been issued to request it through the setting of srdp->cpu_no_qs.b.exp. Reviewed-by: Paul E. McKenney <[email protected]> Signed-off-by: Frederic Weisbecker <[email protected]> Signed-off-by: Joel Fernandes <[email protected]> Signed-off-by: Neeraj Upadhyay (AMD) <[email protected]>
1 parent 86731a2 commit f2e555f

File tree

1 file changed

+7
-7
lines changed

1 file changed

+7
-7
lines changed

kernel/rcu/tree_exp.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,13 @@ static void __maybe_unused sync_exp_reset_tree(void)
141141
raw_spin_lock_irqsave_rcu_node(rnp, flags);
142142
WARN_ON_ONCE(rnp->expmask);
143143
WRITE_ONCE(rnp->expmask, rnp->expmaskinit);
144+
/*
145+
* Need to wait for any blocked tasks as well. Note that
146+
* additional blocking tasks will also block the expedited GP
147+
* until such time as the ->expmask bits are cleared.
148+
*/
149+
if (rcu_is_leaf_node(rnp) && rcu_preempt_has_tasks(rnp))
150+
WRITE_ONCE(rnp->exp_tasks, rnp->blkd_tasks.next);
144151
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
145152
}
146153
}
@@ -393,13 +400,6 @@ static void __sync_rcu_exp_select_node_cpus(struct rcu_exp_work *rewp)
393400
}
394401
mask_ofl_ipi = rnp->expmask & ~mask_ofl_test;
395402

396-
/*
397-
* Need to wait for any blocked tasks as well. Note that
398-
* additional blocking tasks will also block the expedited GP
399-
* until such time as the ->expmask bits are cleared.
400-
*/
401-
if (rcu_preempt_has_tasks(rnp))
402-
WRITE_ONCE(rnp->exp_tasks, rnp->blkd_tasks.next);
403403
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
404404

405405
/* IPI the remaining CPUs for expedited quiescent state. */

0 commit comments

Comments
 (0)