54 lines
2.0 KiB
Diff
54 lines
2.0 KiB
Diff
From: Thomas Gleixner <tglx@linutronix.de>
|
|
Date: Fri, 22 Dec 2017 15:51:13 +0100
|
|
Subject: [PATCH 2/4] nohz: Prevent erroneous tick stop invocations
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.14/older/patches-4.14.8-rt9.tar.xz
|
|
|
|
The conditions in irq_exit() to invoke tick_nohz_irq_exit() are:
|
|
|
|
if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu))
|
|
|
|
This is too permissive in various aspects:
|
|
|
|
1) If need_resched() is set, then the tick cannot be stopped whether
|
|
the CPU is idle or in nohz full mode.
|
|
|
|
2) If need_resched() is not set, but softirqs are pending then this is an
|
|
indication that the softirq code punted and delegated the execution to
|
|
softirqd. need_resched() is not true because the current interrupted
|
|
task takes precedence over softirqd.
|
|
|
|
Invoking tick_nohz_irq_exit() in these cases can cause an endless loop of
|
|
timer interrupts because the timer wheel contains an expired timer, but
|
|
softirqs are not yet executed. So it returns an immediate expiry request,
|
|
which causes the timer to fire immediately again. Lather, rinse and
|
|
repeat....
|
|
|
|
Prevent that by making the conditions proper and only allow invokation when
|
|
in idle or nohz full mode and neither need_resched() nor
|
|
local_softirq_pending() are set.
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
Cc: stable@vger.kernel.org
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
---
|
|
kernel/softirq.c | 3 ++-
|
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/kernel/softirq.c b/kernel/softirq.c
|
|
index 4e09821f9d9e..6d260b1229a1 100644
|
|
--- a/kernel/softirq.c
|
|
+++ b/kernel/softirq.c
|
|
@@ -381,7 +381,8 @@ static inline void tick_irq_exit(void)
|
|
int cpu = smp_processor_id();
|
|
|
|
/* Make sure that timer wheel updates are propagated */
|
|
- if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu)) {
|
|
+ if ((idle_cpu(cpu) || tick_nohz_full_cpu(cpu)) &&
|
|
+ !need_resched() && !local_softirq_pending()) {
|
|
if (!in_interrupt())
|
|
tick_nohz_irq_exit();
|
|
}
|
|
--
|
|
2.15.1
|
|
|