Skip to content

Commit 790da24

Browse files
committed
rcu: Make idle entry report expedited quiescent states
In non-preemptible kernels, an unfortunately timed expedited grace period can result in the rcu_exp_handler() IPI handler setting the rcu_data structure's cpu_no_qs.b.exp field just as the target CPU enters idle. There are situations in which this field will not be checked until after that CPU exits idle. The resulting grace-period latency does not qualify as "expedited". This commit therefore checks this field upon non-preemptible idle entry in the rcu_preempt_deferred_qs() function. It also qualifies the rcu_core() preempt_count() check with IS_ENABLED(CONFIG_PREEMPT_COUNT) to prevent false-positive quiescent states from count-free kernels. Reported-by: Neeraj Upadhyay <neeraju@codeaurora.org> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
1 parent 147f04b commit 790da24

2 files changed

Lines changed: 13 additions & 2 deletions

File tree

kernel/rcu/tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2714,7 +2714,7 @@ static __latent_entropy void rcu_core(void)
27142714
WARN_ON_ONCE(!rdp->beenonline);
27152715

27162716
/* Report any deferred quiescent states if preemption enabled. */
2717-
if (!(preempt_count() & PREEMPT_MASK)) {
2717+
if (IS_ENABLED(CONFIG_PREEMPT_COUNT) && (!(preempt_count() & PREEMPT_MASK))) {
27182718
rcu_preempt_deferred_qs(current);
27192719
} else if (rcu_preempt_need_deferred_qs(current)) {
27202720
set_tsk_need_resched(current);

kernel/rcu/tree_plugin.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,18 @@ static bool rcu_preempt_need_deferred_qs(struct task_struct *t)
927927
{
928928
return false;
929929
}
930-
static void rcu_preempt_deferred_qs(struct task_struct *t) { }
930+
931+
// Except that we do need to respond to a request by an expedited grace
932+
// period for a quiescent state from this CPU. Note that requests from
933+
// tasks are handled when removing the task from the blocked-tasks list
934+
// below.
935+
static void rcu_preempt_deferred_qs(struct task_struct *t)
936+
{
937+
struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
938+
939+
if (rdp->cpu_no_qs.b.exp)
940+
rcu_report_exp_rdp(rdp);
941+
}
931942

932943
/*
933944
* Because there is no preemptible RCU, there can be no readers blocked,

0 commit comments

Comments
 (0)