1 From f13d4f979c518119bba5439dd2364d76d31dcd3f Mon Sep 17 00:00:00 2001
2 From: Salman Qazi <sqazi@google.com>
3 Date: Tue, 12 Oct 2010 07:25:19 -0700
4 Subject: hrtimer: Preserve timer state in remove_hrtimer()
6 From: Salman Qazi <sqazi@google.com>
8 commit f13d4f979c518119bba5439dd2364d76d31dcd3f upstream.
10 The race is described as follows:
14 // state & QUEUED == 0
15 timer->state = CALLBACK
17 timer->f(n) //very long
20 remove_hrtimer // no effect
22 timer->state = CALLBACK |
35 lock this CPU's timer base
37 The bug was introduced with commit ca109491f (hrtimer: removing all ur
38 callback modes) in 2.6.29
40 [ tglx: Feed new state via local variable and add a comment. ]
42 Signed-off-by: Salman Qazi <sqazi@google.com>
43 Cc: akpm@linux-foundation.org
44 Cc: Peter Zijlstra <peterz@infradead.org>
45 LKML-Reference: <20101012142351.8485.21823.stgit@dungbeetle.mtv.corp.google.com>
46 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
47 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
50 kernel/hrtimer.c | 13 +++++++++++--
51 1 file changed, 11 insertions(+), 2 deletions(-)
53 --- a/kernel/hrtimer.c
54 +++ b/kernel/hrtimer.c
55 @@ -936,6 +936,7 @@ static inline int
56 remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
58 if (hrtimer_is_queued(timer)) {
59 + unsigned long state;
63 @@ -949,8 +950,13 @@ remove_hrtimer(struct hrtimer *timer, st
64 debug_deactivate(timer);
65 timer_stats_hrtimer_clear_start_info(timer);
66 reprogram = base->cpu_base == &__get_cpu_var(hrtimer_bases);
67 - __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE,
70 + * We must preserve the CALLBACK state flag here,
71 + * otherwise we could move the timer base in
72 + * switch_hrtimer_base.
74 + state = timer->state & HRTIMER_STATE_CALLBACK;
75 + __remove_hrtimer(timer, base, state, reprogram);
79 @@ -1237,6 +1243,9 @@ static void __run_hrtimer(struct hrtimer
80 BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
81 enqueue_hrtimer(timer, base);
84 + WARN_ON_ONCE(!(timer->state & HRTIMER_STATE_CALLBACK));
86 timer->state &= ~HRTIMER_STATE_CALLBACK;