aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2016-10-24 05:41:56 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-10-25 10:27:39 -0400
commitb831275a3553c32091222ac619cfddd73a5553fb (patch)
tree83869391da1625c235e75b4584dfcff9b0b189ca /kernel
parent07d9a380680d1c0eb51ef87ff2eab5c994949e69 (diff)
timers: Plug locking race vs. timer migration
Linus noticed that lock_timer_base() lacks a READ_ONCE() for accessing the timer flags. As a consequence the compiler is allowed to reload the flags between the initial check for TIMER_MIGRATION and the following timer base computation and the spin lock of the base. While this has not been observed (yet), we need to make sure that it never happens. Fixes: 0eeda71bc30d ("timer: Replace timer base by a cpu index") Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1610241711220.4983@nanos Cc: stable@vger.kernel.org Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/timer.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 2d47980a1bc4..0d4b91c5a374 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -943,7 +943,14 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
943{ 943{
944 for (;;) { 944 for (;;) {
945 struct timer_base *base; 945 struct timer_base *base;
946 u32 tf = timer->flags; 946 u32 tf;
947
948 /*
949 * We need to use READ_ONCE() here, otherwise the compiler
950 * might re-read @tf between the check for TIMER_MIGRATING
951 * and spin_lock().
952 */
953 tf = READ_ONCE(timer->flags);
947 954
948 if (!(tf & TIMER_MIGRATING)) { 955 if (!(tf & TIMER_MIGRATING)) {
949 base = get_timer_base(tf); 956 base = get_timer_base(tf);