mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
timers: Use deferrable base independent of base::nohz_active
commitced6d5c11d
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:500462a9de
("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>
This commit is contained in:
parent
f0f18aa8f7
commit
e4fb2e7e92
1 changed files with 7 additions and 9 deletions
|
@ -814,11 +814,10 @@ static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu)
|
|||
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;
|
||||
}
|
||||
|
@ -828,11 +827,10 @@ static inline struct timer_base *get_timer_this_cpu_base(u32 tflags)
|
|||
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;
|
||||
}
|
||||
|
@ -1644,7 +1642,7 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h)
|
|||
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]));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue