提交 264bb3f7 编写于 作者: X Xunlei Pang 提交者: Ingo Molnar

time: Fix a bug in timekeeping_suspend() with no persistent clock

When there's no persistent clock, normally
timekeeping_suspend_time should always be zero, but this can
break in timekeeping_suspend().

At T1, there was a system suspend, so old_delta was assigned T1.
After some time, one time adjustment happened, and xtime got the
value of T1-dt(0s<dt<2s). Then, there comes another system
suspend soon after this adjustment, obviously we will get a
small negative delta_delta, resulting in a negative
timekeeping_suspend_time.

This is problematic, when doing timekeeping_resume() if there is
no nonstop clocksource for example, it will hit the else leg and
inject the improper sleeptime which is the wrong logic.

So, we can solve this problem by only doing delta related code
when the persistent clock is existent. Actually the code only
makes sense for persistent clock cases.
Signed-off-by: NXunlei Pang <pang.xunlei@linaro.org>
Signed-off-by: NJohn Stultz <john.stultz@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1427945681-29972-18-git-send-email-john.stultz@linaro.orgSigned-off-by: NIngo Molnar <mingo@kernel.org>
上级 814dcf8e
...@@ -1255,7 +1255,7 @@ void __init timekeeping_init(void) ...@@ -1255,7 +1255,7 @@ void __init timekeeping_init(void)
raw_spin_unlock_irqrestore(&timekeeper_lock, flags); raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
} }
/* time in seconds when suspend began */ /* time in seconds when suspend began for persistent clock */
static struct timespec64 timekeeping_suspend_time; static struct timespec64 timekeeping_suspend_time;
/** /**
...@@ -1428,6 +1428,7 @@ int timekeeping_suspend(void) ...@@ -1428,6 +1428,7 @@ int timekeeping_suspend(void)
timekeeping_forward_now(tk); timekeeping_forward_now(tk);
timekeeping_suspended = 1; timekeeping_suspended = 1;
if (has_persistent_clock()) {
/* /*
* To avoid drift caused by repeated suspend/resumes, * To avoid drift caused by repeated suspend/resumes,
* which each can add ~1 second drift error, * which each can add ~1 second drift error,
...@@ -1439,7 +1440,7 @@ int timekeeping_suspend(void) ...@@ -1439,7 +1440,7 @@ int timekeeping_suspend(void)
if (abs(delta_delta.tv_sec) >= 2) { if (abs(delta_delta.tv_sec) >= 2) {
/* /*
* if delta_delta is too large, assume time correction * if delta_delta is too large, assume time correction
* has occured and set old_delta to the current delta. * has occurred and set old_delta to the current delta.
*/ */
old_delta = delta; old_delta = delta;
} else { } else {
...@@ -1447,6 +1448,7 @@ int timekeeping_suspend(void) ...@@ -1447,6 +1448,7 @@ int timekeeping_suspend(void)
timekeeping_suspend_time = timekeeping_suspend_time =
timespec64_add(timekeeping_suspend_time, delta_delta); timespec64_add(timekeeping_suspend_time, delta_delta);
} }
}
timekeeping_update(tk, TK_MIRROR); timekeeping_update(tk, TK_MIRROR);
halt_fast_timekeeper(tk); halt_fast_timekeeper(tk);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册