diff options
Diffstat (limited to 'patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch')
-rw-r--r-- | patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch b/patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch new file mode 100644 index 000000000000..3febe509a913 --- /dev/null +++ b/patches/tick-Fix-timer-storm-since-introduction-of-timersd.patch @@ -0,0 +1,105 @@ +From: Frederic Weisbecker <frederic@kernel.org> +Date: Tue, 5 Apr 2022 03:07:52 +0200 +Subject: [PATCH] tick: Fix timer storm since introduction of timersd + +If timers are pending while the tick is reprogrammed on nohz_mode, the +next expiry is not armed to fire now, it is delayed one jiffy forward +instead so as not to raise an inextinguishable timer storm with such +scenario: + +1) IRQ triggers and queue a timer +2) ksoftirqd() is woken up +3) IRQ tail: timer is reprogrammed to fire now +4) IRQ exit +5) TIMER interrupt +6) goto 3) + +...all that until we finally reach ksoftirqd. + +Unfortunately we are checking the wrong softirq vector bitmask since +timersd kthread has split from ksoftirqd. Timers now have their own +vector state field that must be checked separately. As a result, the +old timer storm is back. This shows up early on boot with extremely long +initcalls: + + [ 333.004807] initcall dquot_init+0x0/0x111 returned 0 after 323822879 usecs + +and the cause is uncovered with the right trace events showing just +10 microseconds between ticks (~100 000 Hz): + +|swapper/-1 1dn.h111 60818582us : hrtimer_expire_entry: hrtimer=00000000e0ef0f6b function=tick_sched_timer now=60415486608 +|swapper/-1 1dn.h111 60818592us : hrtimer_expire_entry: hrtimer=00000000e0ef0f6b function=tick_sched_timer now=60415496082 +|swapper/-1 1dn.h111 60818601us : hrtimer_expire_entry: hrtimer=00000000e0ef0f6b function=tick_sched_timer now=60415505550 + +Fix this by checking the right timer vector state from the nohz code. + +Signed-off-by: Frederic Weisbecker <frederic@kernel.org> +Cc: Mel Gorman <mgorman@suse.de> +Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Cc: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Link: https://lkml.kernel.org/r/20220405010752.1347437-2-frederic@kernel.org +--- + include/linux/interrupt.h | 12 ++++++++++++ + kernel/softirq.c | 7 +------ + kernel/time/tick-sched.c | 2 +- + 3 files changed, 14 insertions(+), 7 deletions(-) + +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -625,9 +625,16 @@ extern void raise_softirq(unsigned int n + + #ifdef CONFIG_PREEMPT_RT + DECLARE_PER_CPU(struct task_struct *, timersd); ++DECLARE_PER_CPU(unsigned long, pending_timer_softirq); ++ + extern void raise_timer_softirq(void); + extern void raise_hrtimer_softirq(void); + ++static inline unsigned int local_pending_timers(void) ++{ ++ return __this_cpu_read(pending_timer_softirq); ++} ++ + #else + static inline void raise_timer_softirq(void) + { +@@ -638,6 +645,11 @@ static inline void raise_hrtimer_softirq + { + raise_softirq_irqoff(HRTIMER_SOFTIRQ); + } ++ ++static inline unsigned int local_pending_timers(void) ++{ ++ return local_softirq_pending(); ++} + #endif + + DECLARE_PER_CPU(struct task_struct *, ksoftirqd); +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -638,12 +638,7 @@ static inline void tick_irq_exit(void) + } + + DEFINE_PER_CPU(struct task_struct *, timersd); +-static DEFINE_PER_CPU(unsigned long, pending_timer_softirq); +- +-static unsigned int local_pending_timers(void) +-{ +- return __this_cpu_read(pending_timer_softirq); +-} ++DEFINE_PER_CPU(unsigned long, pending_timer_softirq); + + static void wake_timersd(void) + { +--- a/kernel/time/tick-sched.c ++++ b/kernel/time/tick-sched.c +@@ -780,7 +780,7 @@ static void tick_nohz_restart(struct tic + + static inline bool local_timer_softirq_pending(void) + { +- return local_softirq_pending() & BIT(TIMER_SOFTIRQ); ++ return local_pending_timers() & BIT(TIMER_SOFTIRQ); + } + + static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu) |