linux/kernel/time
Thomas Gleixner 9bc7491906 hrtimer: Prevent stale expiry time in hrtimer_interrupt()
hrtimer_interrupt() has the following subtle issue:

hrtimer_interrupt()
  lock(cpu_base);
  expires_next = KTIME_MAX;

  expire_timers(CLOCK_MONOTONIC);
  expires = get_next_timer(CLOCK_MONOTONIC);
  if (expires < expires_next)
    expires_next = expires;

  expire_timers(CLOCK_REALTIME);
    unlock(cpu_base);
    wakeup()
    hrtimer_start(CLOCK_MONOTONIC, newtimer);
    lock(cpu_base();  
  expires = get_next_timer(CLOCK_REALTIME);
  if (expires < expires_next)
    expires_next = expires;

So because we already evaluated the next expiring timer of
CLOCK_MONOTONIC we ignore that the expiry time of newtimer might be
earlier than the overall next expiry time in hrtimer_interrupt().

To solve this, remove the caching of the next expiry value from
hrtimer_interrupt() and reevaluate all active clock bases for the next
expiry value. To avoid another code duplication, create a shared
evaluation function and use it for hrtimer_get_next_event(),
hrtimer_force_reprogram() and hrtimer_interrupt().

There is another subtlety in this mechanism:

While hrtimer_interrupt() is running, we want to avoid to touch the
hardware device because we will reprogram it anyway at the end of
hrtimer_interrupt(). This works nicely for hrtimers which get rearmed
via the HRTIMER_RESTART mechanism, because we drop out when the
callback on that CPU is running. But that fails, if a new timer gets
enqueued like in the example above.

This has another implication: While hrtimer_interrupt() is running we
refuse remote enqueueing of timers - see hrtimer_interrupt() and
hrtimer_check_target().

hrtimer_interrupt() tries to prevent this by setting cpu_base->expires
to KTIME_MAX, but that fails if a new timer gets queued.

Prevent both the hardware access and the remote enqueue
explicitely. We can loosen the restriction on the remote enqueue now
due to reevaluation of the next expiry value, but that needs a
seperate patch.

Folded in a fix from Vignesh Radhakrishnan.

Reported-and-tested-by: Stanislav Fomichev <stfomichev@yandex-team.ru>
Based-on-patch-by: Stanislav Fomichev <stfomichev@yandex-team.ru>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: vigneshr@codeaurora.org
Cc: john.stultz@linaro.org
Cc: viresh.kumar@linaro.org
Cc: fweisbec@gmail.com
Cc: cl@linux.com
Cc: stuart.w.hayes@gmail.com
Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1501202049190.5526@nanos
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2015-01-23 12:13:20 +01:00
..
alarmtimer.c alarmtimer: Lock k_itimer during timer callback 2014-09-12 13:59:12 -07:00
clockevents.c clockevents: Prevent shift out of bounds 2014-10-25 10:43:15 +02:00
clocksource.c clocksource: Fix 'clcoksource' typo in comment 2014-10-29 14:48:34 +01:00
hrtimer.c hrtimer: Prevent stale expiry time in hrtimer_interrupt() 2015-01-23 12:13:20 +01:00
itimer.c time/timers: Move all time(r) related files into kernel/time 2014-06-23 11:22:35 +02:00
jiffies.c time: Fix overflow when HZ is smaller than 60 2014-02-06 16:01:40 +01:00
Kconfig clocksource: Move cycle_last validation to core code 2014-07-23 15:01:51 -07:00
Makefile time: Rename udelay_test.c to test_udelay.c 2014-11-21 11:59:55 -08:00
ntp_internal.h timekeeping: Convert timekeeping core to use timespec64s 2014-07-23 10:17:54 -07:00
ntp.c timekeeping: Provide timespec64 based interfaces 2014-07-23 10:17:55 -07:00
posix-clock.c kernel: Fix files explicitly needing EXPORT_SYMBOL infrastructure 2011-10-31 19:30:05 -04:00
posix-cpu-timers.c sched/cputime: Fix cpu_timer_sample_group() double accounting 2014-11-16 10:04:18 +01:00
posix-timers.c posix-timers: Fix stack info leak in timer_create() 2014-10-25 10:43:15 +02:00
sched_clock.c sched_clock: Avoid corrupting hrtimer tree during suspend 2014-07-24 12:02:49 +02:00
test_udelay.c time: Rename udelay_test.c to test_udelay.c 2014-11-21 11:59:55 -08:00
tick-broadcast-hrtimer.c tick: Fixup more fallout from hrtimer broadcast mode 2014-02-09 15:11:47 +01:00
tick-broadcast.c time: Replace __get_cpu_var uses 2014-08-26 13:45:44 -04:00
tick-common.c Merge branch 'for-3.18-consistent-ops' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu 2014-10-15 07:48:18 +02:00
tick-internal.h nohz: Move nohz full init call to tick init 2014-09-13 18:34:44 +02:00
tick-oneshot.c time: Replace __get_cpu_var uses 2014-08-26 13:45:44 -04:00
tick-sched.c Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip 2014-12-19 13:29:20 -08:00
time.c Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux 2014-12-15 15:52:01 -08:00
timeconst.bc time/timers: Move all time(r) related files into kernel/time 2014-06-23 11:22:35 +02:00
timeconv.c
timekeeping_debug.c timekeeping: Convert timekeeping core to use timespec64s 2014-07-23 10:17:54 -07:00
timekeeping_internal.h clocksource: Move cycle_last validation to core code 2014-07-23 15:01:51 -07:00
timekeeping.c Merge branch 'timers-2038-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip 2014-12-10 10:13:28 -08:00
timekeeping.h time: Consolidate the time accessor prototypes 2014-07-23 10:17:54 -07:00
timer_list.c timer_list: correct the iterator for timer_list 2013-08-28 19:26:38 -07:00
timer_stats.c timer stats: Add a 'Collection: active/inactive' line to timer usage statistics 2013-10-10 09:59:25 +02:00
timer.c rcu: Remove "cpu" argument to rcu_check_callbacks() 2014-11-03 19:20:11 -08:00