diff options
author | John Stultz <john.stultz@linaro.org> | 2012-03-15 00:38:15 +0100 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2012-03-16 02:17:54 +0100 |
commit | f695cf94837de53864180400cbac42cfa370426f (patch) | |
tree | 9bb91a9b8c5a1291a083a37e790da00d477b18f8 /kernel/time | |
parent | time: x86: Fix race switching from vsyscall to non-vsyscall clock (diff) | |
download | linux-f695cf94837de53864180400cbac42cfa370426f.tar.xz linux-f695cf94837de53864180400cbac42cfa370426f.zip |
time: Fix change_clocksource locking
change_clocksource() fails to grab locks or call timekeeping_update(),
which leaves a race window for time inconsistencies.
This adds proper locking and a call to timekeeping_update() to fix this.
CC: Andy Lutomirski <luto@amacapital.net>
CC: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/timekeeping.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 403c2a092830..b53da5ecbea2 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -448,9 +448,12 @@ EXPORT_SYMBOL(timekeeping_inject_offset); static int change_clocksource(void *data) { struct clocksource *new, *old; + unsigned long flags; new = (struct clocksource *) data; + write_seqlock_irqsave(&timekeeper.lock, flags); + timekeeping_forward_now(); if (!new->enable || new->enable(new) == 0) { old = timekeeper.clock; @@ -458,6 +461,10 @@ static int change_clocksource(void *data) if (old->disable) old->disable(old); } + timekeeping_update(true); + + write_sequnlock_irqrestore(&timekeeper.lock, flags); + return 0; } |