linux/kernel/time
Thomas Gleixner 1f73a9806b tick: Prevent uncontrolled switch to oneshot mode
When the system switches from periodic to oneshot mode, the broadcast
logic causes a possibility that a CPU which has not yet switched to
oneshot mode puts its own clock event device into oneshot mode without
updating the state and the timer handler.

CPU0				CPU1
				per cpu tickdev is in periodic mode
				and switched to broadcast

Switch to oneshot mode
 tick_broadcast_switch_to_oneshot()
  cpumask_copy(tick_oneshot_broacast_mask,
	       tick_broadcast_mask);

  broadcast device mode = oneshot

				Timer interrupt
						
				irq_enter()
				 tick_check_oneshot_broadcast()
				  dev->set_mode(ONESHOT);

				tick_handle_periodic()
				 if (dev->mode == ONESHOT)
				   dev->next_event += period;
				   FAIL.

We fail, because dev->next_event contains KTIME_MAX, if the device was
in periodic mode before the uncontrolled switch to oneshot happened.

We must copy the broadcast bits over to the oneshot mask, because
otherwise a CPU which relies on the broadcast would not been woken up
anymore after the broadcast device switched to oneshot mode.

So we need to verify in tick_check_oneshot_broadcast() whether the CPU
has already switched to oneshot mode. If not, leave the device
untouched and let the CPU switch controlled into oneshot mode.

This is a long standing bug, which was never noticed, because the main
user of the broadcast x86 cannot run into that scenario, AFAICT. The
nonarchitected timer mess of ARM creates a gazillion of differently
broken abominations which trigger the shortcomings of that broadcast
code, which better had never been necessary in the first place.

Reported-and-tested-by: Stehle Vincent-B46079 <B46079@freescale.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Cc: John Stultz <john.stultz@linaro.org>,
Cc: Mark Rutland <mark.rutland@arm.com>
Link: http://lkml.kernel.org/r/alpine.DEB.2.02.1307012153060.4013@ionos.tec.linutronix.de
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2013-07-02 14:26:45 +02:00
..
alarmtimer.c alarmtimer: Export symbols of functions declared in linux/alarmtimer.h 2013-06-12 14:02:12 -07:00
clockevents.c clockevents: Implement unbind functionality 2013-05-16 11:09:18 +02:00
clocksource.c clocksource: Implement clocksource_select_fallback() for CONFIG_ARCH_USES_GETTIMEOFFSET=y 2013-05-28 09:48:46 +02:00
jiffies.c time: Kill xtime_lock, replacing it with jiffies_lock 2012-11-13 14:08:23 -05:00
Kconfig Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip 2013-05-15 14:05:17 -07:00
Makefile sched_clock: Make ARM's sched_clock generic for all architectures 2013-06-12 14:02:13 -07:00
ntp_internal.h ntp: Rework do_adjtimex to take timespec and tai arguments 2013-04-04 13:18:15 -07:00
ntp.c ntp: Remove ntp_lock, using the timekeeping locks to protect ntp state 2013-04-04 13:18:17 -07:00
posix-clock.c kernel: Fix files explicitly needing EXPORT_SYMBOL infrastructure 2011-10-31 19:30:05 -04:00
sched_clock.c ARM: sched_clock: Load cycle count after epoch stabilizes 2013-06-17 15:56:11 -07:00
tick-broadcast.c tick: Prevent uncontrolled switch to oneshot mode 2013-07-02 14:26:45 +02:00
tick-common.c clockevents: Prefer CPU local devices over global devices 2013-06-24 22:27:36 +02:00
tick-internal.h clockevents: Define CS_NAME_LEN unconditionally 2013-05-28 09:28:02 +02:00
tick-oneshot.c clockevents: Make minimum delay adjustments configurable 2011-09-08 11:10:56 +02:00
tick-sched.c Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip 2013-05-15 14:05:17 -07:00
timeconv.c time: add function to convert between calendar time and broken-down time for universal use 2009-09-24 07:20:56 -07:00
timekeeping_debug.c power: Add option to log time spent in suspend 2013-05-29 12:57:34 -07:00
timekeeping_internal.h power: Add option to log time spent in suspend 2013-05-29 12:57:34 -07:00
timekeeping.c timekeeping: Indicate that clock was set in the pvclock gtod notifier 2013-06-28 23:15:06 +02:00
timer_list.c timer_list: Convert timer list to be a proper seq_file 2013-04-17 20:51:02 +02:00
timer_stats.c locking, timer_stats: Annotate table_lock as raw 2011-09-13 11:12:00 +02:00