diff options
author | Ingo Molnar <mingo@kernel.org> | 2012-08-04 15:21:14 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-08-05 06:37:14 -0400 |
commit | 1d17d17484d40f2d5b35c79518597a2b25296996 (patch) | |
tree | a11000cb9a7197b5d70573d0faa417cb36ba0e4b /kernel | |
parent | e7882d6c40874a5b5033ca85f7508a602a60b662 (diff) |
time: Fix adjustment cleanup bug in timekeeping_adjust()
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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/time/timekeeping.c | 31 |
1 files changed, 17 insertions, 14 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 2988bc819187..e16af197a2bc 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -923,20 +923,22 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset) | |||
923 | if (likely(error <= interval)) | 923 | if (likely(error <= interval)) |
924 | adj = 1; | 924 | adj = 1; |
925 | else | 925 | else |
926 | adj = timekeeping_bigadjust(tk, error, &interval, | 926 | adj = timekeeping_bigadjust(tk, error, &interval, &offset); |
927 | &offset); | 927 | } else { |
928 | } else if (error < -interval) { | 928 | if (error < -interval) { |
929 | /* See comment above, this is just switched for the negative */ | 929 | /* See comment above, this is just switched for the negative */ |
930 | error >>= 2; | 930 | error >>= 2; |
931 | if (likely(error >= -interval)) { | 931 | if (likely(error >= -interval)) { |
932 | adj = -1; | 932 | adj = -1; |
933 | interval = -interval; | 933 | interval = -interval; |
934 | offset = -offset; | 934 | offset = -offset; |
935 | } else | 935 | } else { |
936 | adj = timekeeping_bigadjust(tk, error, &interval, | 936 | adj = timekeeping_bigadjust(tk, error, &interval, &offset); |
937 | &offset); | 937 | } |
938 | } else | 938 | } else { |
939 | return; | 939 | goto out_adjust; |
940 | } | ||
941 | } | ||
940 | 942 | ||
941 | if (unlikely(tk->clock->maxadj && | 943 | if (unlikely(tk->clock->maxadj && |
942 | (tk->mult + adj > tk->clock->mult + tk->clock->maxadj))) { | 944 | (tk->mult + adj > tk->clock->mult + tk->clock->maxadj))) { |
@@ -999,6 +1001,7 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset) | |||
999 | tk->xtime_nsec -= offset; | 1001 | tk->xtime_nsec -= offset; |
1000 | tk->ntp_error -= (interval - offset) << tk->ntp_error_shift; | 1002 | tk->ntp_error -= (interval - offset) << tk->ntp_error_shift; |
1001 | 1003 | ||
1004 | out_adjust: | ||
1002 | /* | 1005 | /* |
1003 | * It may be possible that when we entered this function, xtime_nsec | 1006 | * It may be possible that when we entered this function, xtime_nsec |
1004 | * was very small. Further, if we're slightly speeding the clocksource | 1007 | * was very small. Further, if we're slightly speeding the clocksource |