77 lines
3.0 KiB
Diff
77 lines
3.0 KiB
Diff
From: Anna-Maria Gleixner <anna-maria@linutronix.de>
|
|
Date: Fri, 22 Dec 2017 15:51:12 +0100
|
|
Subject: [PATCH 1/4] timer: Use deferrable base independent of
|
|
base::nohz_active
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.14/older/patches-4.14.8-rt9.tar.xz
|
|
|
|
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>
|
|
Cc: stable@vger.kernel.org
|
|
Cc: rt@linutronix.de
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
---
|
|
kernel/time/timer.c | 16 +++++++---------
|
|
1 file changed, 7 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
|
|
index f2674a056c26..fdfaf4f3bcfa 100644
|
|
--- a/kernel/time/timer.c
|
|
+++ b/kernel/time/timer.c
|
|
@@ -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]));
|
|
}
|
|
|
|
--
|
|
2.15.1
|
|
|