diff options
author | Peter Zijlstra <peterz@infradead.org> | 2015-06-11 08:46:45 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-06-18 18:09:56 -0400 |
commit | 8edfb0362e8e52dec2de08fa163af01c9da2c9d0 (patch) | |
tree | 5f607cf35b8c625695eb7cc3d357432f733185fa /kernel/time/hrtimer.c | |
parent | c04dca02bc73096435a5c36efd5ccb2171edcbe1 (diff) |
hrtimer: Fix hrtimer_is_queued() hole
A queued hrtimer that gets restarted (hrtimer_start*() while
hrtimer_is_queued()) will briefly appear as unqueued/inactive, even
though the timer has always been active, we just moved it.
Close this hole by preserving timer->state in
hrtimer_start_range_ns()'s remove_hrtimer() call.
Reported-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: ktkhai@parallels.com
Cc: rostedt@goodmis.org
Cc: juri.lelli@gmail.com
Cc: pang.xunlei@linaro.org
Cc: wanpeng.li@linux.intel.com
Cc: umgwanakikbuti@gmail.com
Link: http://lkml.kernel.org/r/20150611124743.175989138@infradead.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/hrtimer.c')
-rw-r--r-- | kernel/time/hrtimer.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index b1b795e5e0b1..1604157374d7 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c | |||
@@ -889,10 +889,10 @@ static void __remove_hrtimer(struct hrtimer *timer, | |||
889 | * remove hrtimer, called with base lock held | 889 | * remove hrtimer, called with base lock held |
890 | */ | 890 | */ |
891 | static inline int | 891 | static inline int |
892 | remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) | 892 | remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool restart) |
893 | { | 893 | { |
894 | if (hrtimer_is_queued(timer)) { | 894 | if (hrtimer_is_queued(timer)) { |
895 | unsigned long state; | 895 | unsigned long state = timer->state; |
896 | int reprogram; | 896 | int reprogram; |
897 | 897 | ||
898 | /* | 898 | /* |
@@ -906,12 +906,15 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) | |||
906 | debug_deactivate(timer); | 906 | debug_deactivate(timer); |
907 | timer_stats_hrtimer_clear_start_info(timer); | 907 | timer_stats_hrtimer_clear_start_info(timer); |
908 | reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); | 908 | reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); |
909 | /* | 909 | |
910 | * We must preserve the CALLBACK state flag here, | 910 | if (!restart) { |
911 | * otherwise we could move the timer base in | 911 | /* |
912 | * switch_hrtimer_base. | 912 | * We must preserve the CALLBACK state flag here, |
913 | */ | 913 | * otherwise we could move the timer base in |
914 | state = timer->state & HRTIMER_STATE_CALLBACK; | 914 | * switch_hrtimer_base. |
915 | */ | ||
916 | state &= HRTIMER_STATE_CALLBACK; | ||
917 | } | ||
915 | __remove_hrtimer(timer, base, state, reprogram); | 918 | __remove_hrtimer(timer, base, state, reprogram); |
916 | return 1; | 919 | return 1; |
917 | } | 920 | } |
@@ -936,7 +939,7 @@ void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, | |||
936 | base = lock_hrtimer_base(timer, &flags); | 939 | base = lock_hrtimer_base(timer, &flags); |
937 | 940 | ||
938 | /* Remove an active timer from the queue: */ | 941 | /* Remove an active timer from the queue: */ |
939 | remove_hrtimer(timer, base); | 942 | remove_hrtimer(timer, base, true); |
940 | 943 | ||
941 | if (mode & HRTIMER_MODE_REL) { | 944 | if (mode & HRTIMER_MODE_REL) { |
942 | tim = ktime_add_safe(tim, base->get_time()); | 945 | tim = ktime_add_safe(tim, base->get_time()); |
@@ -1005,7 +1008,7 @@ int hrtimer_try_to_cancel(struct hrtimer *timer) | |||
1005 | base = lock_hrtimer_base(timer, &flags); | 1008 | base = lock_hrtimer_base(timer, &flags); |
1006 | 1009 | ||
1007 | if (!hrtimer_callback_running(timer)) | 1010 | if (!hrtimer_callback_running(timer)) |
1008 | ret = remove_hrtimer(timer, base); | 1011 | ret = remove_hrtimer(timer, base, false); |
1009 | 1012 | ||
1010 | unlock_hrtimer_base(timer, &flags); | 1013 | unlock_hrtimer_base(timer, &flags); |
1011 | 1014 | ||