diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2012-05-23 01:10:24 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2012-07-02 15:34:24 -0400 |
commit | 62fde6edf12b60fddb13a3f0a779c8be0bb7447e (patch) | |
tree | 2fa26e28ce311acb29c60f1595235240be6e7d97 /kernel/rcutree.c | |
parent | 28f5c693d03530eb15c5354f758b789189b98c37 (diff) |
rcu: Make __call_rcu() handle invocation from idle
Although __call_rcu() is handled correctly when called from a momentary
non-idle period, if it is called on a CPU that RCU believes to be idle
on RCU_FAST_NO_HZ kernels, the callback might be indefinitely postponed.
This commit therefore ensures that RCU is aware of the new callback and
has a chance to force the CPU out of dyntick-idle mode when a new callback
is posted.
Reported-by: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Diffstat (limited to 'kernel/rcutree.c')
-rw-r--r-- | kernel/rcutree.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 89addada3e3a..a4a9c916ad36 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -585,8 +585,6 @@ void rcu_nmi_exit(void) | |||
585 | WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); | 585 | WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); |
586 | } | 586 | } |
587 | 587 | ||
588 | #ifdef CONFIG_PROVE_RCU | ||
589 | |||
590 | /** | 588 | /** |
591 | * rcu_is_cpu_idle - see if RCU thinks that the current CPU is idle | 589 | * rcu_is_cpu_idle - see if RCU thinks that the current CPU is idle |
592 | * | 590 | * |
@@ -604,7 +602,7 @@ int rcu_is_cpu_idle(void) | |||
604 | } | 602 | } |
605 | EXPORT_SYMBOL(rcu_is_cpu_idle); | 603 | EXPORT_SYMBOL(rcu_is_cpu_idle); |
606 | 604 | ||
607 | #ifdef CONFIG_HOTPLUG_CPU | 605 | #if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU) |
608 | 606 | ||
609 | /* | 607 | /* |
610 | * Is the current CPU online? Disable preemption to avoid false positives | 608 | * Is the current CPU online? Disable preemption to avoid false positives |
@@ -645,9 +643,7 @@ bool rcu_lockdep_current_cpu_online(void) | |||
645 | } | 643 | } |
646 | EXPORT_SYMBOL_GPL(rcu_lockdep_current_cpu_online); | 644 | EXPORT_SYMBOL_GPL(rcu_lockdep_current_cpu_online); |
647 | 645 | ||
648 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ | 646 | #endif /* #if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU) */ |
649 | |||
650 | #endif /* #ifdef CONFIG_PROVE_RCU */ | ||
651 | 647 | ||
652 | /** | 648 | /** |
653 | * rcu_is_cpu_rrupt_from_idle - see if idle or immediately interrupted from idle | 649 | * rcu_is_cpu_rrupt_from_idle - see if idle or immediately interrupted from idle |
@@ -1904,6 +1900,13 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | |||
1904 | else | 1900 | else |
1905 | trace_rcu_callback(rsp->name, head, rdp->qlen_lazy, rdp->qlen); | 1901 | trace_rcu_callback(rsp->name, head, rdp->qlen_lazy, rdp->qlen); |
1906 | 1902 | ||
1903 | /* | ||
1904 | * If called from an extended quiescent state, invoke the RCU | ||
1905 | * core in order to force a re-evaluation of RCU's idleness. | ||
1906 | */ | ||
1907 | if (rcu_is_cpu_idle()) | ||
1908 | invoke_rcu_core(); | ||
1909 | |||
1907 | /* If interrupts were disabled, don't dive into RCU core. */ | 1910 | /* If interrupts were disabled, don't dive into RCU core. */ |
1908 | if (irqs_disabled_flags(flags)) { | 1911 | if (irqs_disabled_flags(flags)) { |
1909 | local_irq_restore(flags); | 1912 | local_irq_restore(flags); |