Skip to content

Commit 806f04e

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
rcu: Allow for smp_call_function() running callbacks from idle
Current RCU hard relies on smp_call_function() callbacks running from interrupt context. A pending optimization is going to break that, it will allow idle CPUs to run the callbacks from the idle loop. This avoids raising the IPI on the requesting CPU and avoids handling an exception on the receiving CPU. Change rcu_is_cpu_rrupt_from_idle() to also accept task context, provided it is the idle task. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Reviewed-by: Paul E. McKenney <[email protected]> Reviewed-by: Joel Fernandes (Google) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b1fcf9b commit 806f04e

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

kernel/rcu/tree.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -418,16 +418,23 @@ void rcu_momentary_dyntick_idle(void)
418418
EXPORT_SYMBOL_GPL(rcu_momentary_dyntick_idle);
419419

420420
/**
421-
* rcu_is_cpu_rrupt_from_idle - see if interrupted from idle
421+
* rcu_is_cpu_rrupt_from_idle - see if 'interrupted' from idle
422422
*
423423
* If the current CPU is idle and running at a first-level (not nested)
424-
* interrupt from idle, return true. The caller must have at least
425-
* disabled preemption.
424+
* interrupt, or directly, from idle, return true.
425+
*
426+
* The caller must have at least disabled IRQs.
426427
*/
427428
static int rcu_is_cpu_rrupt_from_idle(void)
428429
{
429-
/* Called only from within the scheduling-clock interrupt */
430-
lockdep_assert_in_irq();
430+
long nesting;
431+
432+
/*
433+
* Usually called from the tick; but also used from smp_function_call()
434+
* for expedited grace periods. This latter can result in running from
435+
* the idle task, instead of an actual IPI.
436+
*/
437+
lockdep_assert_irqs_disabled();
431438

432439
/* Check for counter underflows */
433440
RCU_LOCKDEP_WARN(__this_cpu_read(rcu_data.dynticks_nesting) < 0,
@@ -436,9 +443,15 @@ static int rcu_is_cpu_rrupt_from_idle(void)
436443
"RCU dynticks_nmi_nesting counter underflow/zero!");
437444

438445
/* Are we at first interrupt nesting level? */
439-
if (__this_cpu_read(rcu_data.dynticks_nmi_nesting) != 1)
446+
nesting = __this_cpu_read(rcu_data.dynticks_nmi_nesting);
447+
if (nesting > 1)
440448
return false;
441449

450+
/*
451+
* If we're not in an interrupt, we must be in the idle task!
452+
*/
453+
WARN_ON_ONCE(!nesting && !is_idle_task(current));
454+
442455
/* Does CPU appear to be idle from an RCU standpoint? */
443456
return __this_cpu_read(rcu_data.dynticks_nesting) == 0;
444457
}

0 commit comments

Comments
 (0)