[RFC] tick/nohz: schedule TIMER_SOFTIRQ immediately for expired timers

From: Octavian Purdila
Date: Wed May 24 2017 - 08:39:57 EST


Currently, when detecting expired timers in tick_nohz_stop_sched_tick
we just schedule a new hrtimer and let its handler to schedule
TIMER_SOFITRQ.

This can lead to indefinite timer stalls if the system is busy with a
stream of interrupts that have the period shorter or about the same
with the value of the minimum delay of the current clocksource driver:

-> idle
-> IRQ (time = x)
-> irq_exit -> tick_nohz_irq_exit -> tick_nohz_stop_sched_tick
-> tick_nohz_restart
-> cancel hrtimer (set clocksource event to x + max_delay)
-> set clocksource to x + min_delay
...
-> IRQ (time = y, where y < x + min_delay)
-> irq_exit -> tick_nohz_irq_exit -> tick_nohz_stop_sched_tick
-> tick_nohz_restart
-> cancel hrtimer (set clocksource event to x + max_delay)
-> set clocksource to y + min_delay

So, instead of prodding the hrtimer interrupt, schedule TIMER_SOFTIRQ
since we know that timers are ready. The timers will run either at the
next interrupt or from ksoftirq so no hrtimer interrupt is
needed. This also avoids spurious programming of the clocksource in
this scenario.

Signed-off-by: Octavian Purdila <octavian.purdila@xxxxxxx>
---
kernel/time/tick-sched.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 3bcb61b..0a30278 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -727,9 +727,16 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
*
* Only once we exit the idle loop will we re-enable the tick,
* see tick_nohz_idle_exit().
+ *
+ * Also, make sure we schedule TIMER_SOFTIRQ now instead of
+ * relying on the hrtimer interrupt to do it to avoid
+ * postponing processing of expired timers. If we have a
+ * constant stream of interrupts with a period shorter than
+ * the minimum delay of the current clocksource we can end up
+ * postponing the timers indefinitely.
*/
if (delta == 0) {
- tick_nohz_restart(ts, now);
+ raise_softirq(TIMER_SOFTIRQ);
goto out;
}
}
--
2.7.4