]> Pileus Git - ~andy/linux/commitdiff
time: Fix adjustment cleanup bug in timekeeping_adjust()
authorIngo Molnar <mingo@kernel.org>
Sat, 4 Aug 2012 19:21:14 +0000 (21:21 +0200)
committerIngo Molnar <mingo@kernel.org>
Sun, 5 Aug 2012 10:37:14 +0000 (12:37 +0200)
Tetsuo Handa reported that sporadically the system clock starts
counting up too quickly which is enough to confuse the hangcheck
timer to print a bogus stall warning.

Commit 2a8c0883 "time: Move xtime_nsec adjustment underflow handling
timekeeping_adjust" overlooked this exit path:

        } else
                return;

which should really be a proper exit sequence, fixing the bug as a
side effect.

Also make the flow more readable by properly balancing curly
braces.

Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> wrote:
Tested-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> wrote:
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: john.stultz@linaro.org
Cc: a.p.zijlstra@chello.nl
Cc: richardcochran@gmail.com
Cc: prarit@redhat.com
Link: http://lkml.kernel.org/r/20120804192114.GA28347@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
kernel/time/timekeeping.c

index 2988bc8191871d4bb5aed9e349634ab11c664caf..e16af197a2bc54c8f81070a1043ed1f81923679f 100644 (file)
@@ -923,20 +923,22 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
                if (likely(error <= interval))
                        adj = 1;
                else
-                       adj = timekeeping_bigadjust(tk, error, &interval,
-                                                       &offset);
-       } else if (error < -interval) {
-               /* See comment above, this is just switched for the negative */
-               error >>= 2;
-               if (likely(error >= -interval)) {
-                       adj = -1;
-                       interval = -interval;
-                       offset = -offset;
-               } else
-                       adj = timekeeping_bigadjust(tk, error, &interval,
-                                                       &offset);
-       } else
-               return;
+                       adj = timekeeping_bigadjust(tk, error, &interval, &offset);
+       } else {
+               if (error < -interval) {
+                       /* See comment above, this is just switched for the negative */
+                       error >>= 2;
+                       if (likely(error >= -interval)) {
+                               adj = -1;
+                               interval = -interval;
+                               offset = -offset;
+                       } else {
+                               adj = timekeeping_bigadjust(tk, error, &interval, &offset);
+                       }
+               } else {
+                       goto out_adjust;
+               }
+       }
 
        if (unlikely(tk->clock->maxadj &&
                (tk->mult + adj > tk->clock->mult + tk->clock->maxadj))) {
@@ -999,6 +1001,7 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
        tk->xtime_nsec -= offset;
        tk->ntp_error -= (interval - offset) << tk->ntp_error_shift;
 
+out_adjust:
        /*
         * It may be possible that when we entered this function, xtime_nsec
         * was very small.  Further, if we're slightly speeding the clocksource