time: Fix change_clocksource locking
authorJohn Stultz <john.stultz@linaro.org>
Wed, 14 Mar 2012 23:38:15 +0000 (16:38 -0700)
committerJohn Stultz <john.stultz@linaro.org>
Fri, 16 Mar 2012 01:17:54 +0000 (18:17 -0700)
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>
kernel/time/timekeeping.c

index 403c2a092830cf91f1225302405f2c8cfd483e8a..b53da5ecbea2e690490ed6395aa47e45bf0bfda0 100644 (file)
@@ -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;
 }