| From ced6d5c11d3e7b342f1a80f908e6756ebd4b8ddd Mon Sep 17 00:00:00 2001 |
| From: Anna-Maria Gleixner <anna-maria@linutronix.de> |
| Date: Fri, 22 Dec 2017 15:51:12 +0100 |
| Subject: timers: Use deferrable base independent of base::nohz_active |
| |
| From: Anna-Maria Gleixner <anna-maria@linutronix.de> |
| |
| commit ced6d5c11d3e7b342f1a80f908e6756ebd4b8ddd upstream. |
| |
| During boot and before base::nohz_active is set in the timer bases, deferrable |
| timers are enqueued into the standard timer base. This works correctly as |
| long as base::nohz_active is false. |
| |
| Once it base::nohz_active is set and a timer which was enqueued before that |
| is accessed the lock selector code choses the lock of the deferred |
| base. This causes unlocked access to the standard base and in case the |
| timer is removed it does not clear the pending flag in the standard base |
| bitmap which causes get_next_timer_interrupt() to return bogus values. |
| |
| To prevent that, the deferrable timers must be enqueued in the deferrable |
| base, even when base::nohz_active is not set. Those deferrable timers also |
| need to be expired unconditional. |
| |
| Fixes: 500462a9de65 ("timers: Switch to a non-cascading wheel") |
| Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Reviewed-by: Frederic Weisbecker <fweisbec@gmail.com> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Sebastian Siewior <bigeasy@linutronix.de> |
| Cc: rt@linutronix.de |
| Cc: Paul McKenney <paulmck@linux.vnet.ibm.com> |
| Link: https://lkml.kernel.org/r/20171222145337.633328378@linutronix.de |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/time/timer.c | 16 +++++++--------- |
| 1 file changed, 7 insertions(+), 9 deletions(-) |
| |
| --- a/kernel/time/timer.c |
| +++ b/kernel/time/timer.c |
| @@ -849,11 +849,10 @@ static inline struct timer_base *get_tim |
| struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_STD], cpu); |
| |
| /* |
| - * If the timer is deferrable and nohz is active then we need to use |
| - * the deferrable base. |
| + * If the timer is deferrable and NO_HZ_COMMON is set then we need |
| + * to use the deferrable base. |
| */ |
| - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && |
| - (tflags & TIMER_DEFERRABLE)) |
| + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && (tflags & TIMER_DEFERRABLE)) |
| base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu); |
| return base; |
| } |
| @@ -863,11 +862,10 @@ static inline struct timer_base *get_tim |
| struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); |
| |
| /* |
| - * If the timer is deferrable and nohz is active then we need to use |
| - * the deferrable base. |
| + * If the timer is deferrable and NO_HZ_COMMON is set then we need |
| + * to use the deferrable base. |
| */ |
| - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && |
| - (tflags & TIMER_DEFERRABLE)) |
| + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && (tflags & TIMER_DEFERRABLE)) |
| base = this_cpu_ptr(&timer_bases[BASE_DEF]); |
| return base; |
| } |
| @@ -1684,7 +1682,7 @@ static __latent_entropy void run_timer_s |
| base->must_forward_clk = false; |
| |
| __run_timers(base); |
| - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) |
| + if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) |
| __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); |
| } |
| |