All of lore.kernel.org
 help / color / mirror / Atom feed
From: Xunlei Pang <xlpang@126.com>
To: linux-kernel@vger.kernel.org
Cc: rtc-linux@googlegroups.com, Thomas Gleixner <tglx@linutronix.de>,
	Alessandro Zummo <a.zummo@towertech.it>,
	John Stultz <john.stultz@linaro.org>,
	Arnd Bergmann <arnd.bergmann@linaro.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Xunlei Pang <pang.xunlei@linaro.org>
Subject: [PATCH v5 2/4] time: Fix a bug in timekeeping_suspend() with no persistent clock
Date: Mon,  9 Mar 2015 14:27:49 +0800	[thread overview]
Message-ID: <1425882471-5591-2-git-send-email-xlpang@126.com> (raw)
In-Reply-To: <1425882471-5591-1-git-send-email-xlpang@126.com>

From: Xunlei Pang <pang.xunlei@linaro.org>

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.

This patch also improves the name of timekeeping_suspend_time.

Signed-off-by: Xunlei Pang <pang.xunlei@linaro.org>
---
 kernel/time/timekeeping.c | 50 ++++++++++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 22 deletions(-)

diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 49b1643..2aae419 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1100,8 +1100,8 @@ void __init timekeeping_init(void)
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 }
 
-/* time in seconds when suspend began */
-static struct timespec64 timekeeping_suspend_time;
+/* time in seconds when suspend began for persistent clock */
+static struct timespec64 persistent_clock_suspendtime;
 
 /**
  * __timekeeping_inject_sleeptime - Internal function to add sleep interval
@@ -1229,8 +1229,9 @@ static void timekeeping_resume(void)
 
 		ts_delta = ns_to_timespec64(nsec);
 		suspendtime_found = true;
-	} else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
-		ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time);
+	} else if (timespec64_compare(&ts_new,
+				    &persistent_clock_suspendtime) > 0) {
+		ts_delta = timespec64_sub(ts_new, persistent_clock_suspendtime);
 		suspendtime_found = true;
 	}
 
@@ -1262,14 +1263,15 @@ static int timekeeping_suspend(void)
 	struct timespec tmp;
 
 	read_persistent_clock(&tmp);
-	timekeeping_suspend_time = timespec_to_timespec64(tmp);
+	persistent_clock_suspendtime = timespec_to_timespec64(tmp);
 
 	/*
 	 * On some systems the persistent_clock can not be detected at
 	 * timekeeping_init by its return value, so if we see a valid
 	 * value returned, update the persistent_clock_exists flag.
 	 */
-	if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec)
+	if (persistent_clock_suspendtime.tv_sec ||
+	    persistent_clock_suspendtime.tv_nsec)
 		persistent_clock_exist = true;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
@@ -1277,24 +1279,28 @@ static int timekeeping_suspend(void)
 	timekeeping_forward_now(tk);
 	timekeeping_suspended = 1;
 
-	/*
-	 * To avoid drift caused by repeated suspend/resumes,
-	 * which each can add ~1 second drift error,
-	 * try to compensate so the difference in system time
-	 * and persistent_clock time stays close to constant.
-	 */
-	delta = timespec64_sub(tk_xtime(tk), timekeeping_suspend_time);
-	delta_delta = timespec64_sub(delta, old_delta);
-	if (abs(delta_delta.tv_sec)  >= 2) {
+	if (has_persistent_clock()) {
 		/*
-		 * if delta_delta is too large, assume time correction
-		 * has occured and set old_delta to the current delta.
+		 * To avoid drift caused by repeated suspend/resumes,
+		 * which each can add ~1 second drift error,
+		 * try to compensate so the difference in system time
+		 * and persistent_clock time stays close to constant.
 		 */
-		old_delta = delta;
-	} else {
-		/* Otherwise try to adjust old_system to compensate */
-		timekeeping_suspend_time =
-			timespec64_add(timekeeping_suspend_time, delta_delta);
+		delta = timespec64_sub(tk_xtime(tk),
+					persistent_clock_suspendtime);
+		delta_delta = timespec64_sub(delta, old_delta);
+		if (abs(delta_delta.tv_sec) >= 2) {
+			/*
+			 * if delta_delta is too large, assume time correction
+			 * has occurred and set old_delta to the current delta.
+			 */
+			old_delta = delta;
+		} else {
+			/* Otherwise try to adjust old_system to compensate */
+			persistent_clock_suspendtime =
+				timespec64_add(persistent_clock_suspendtime,
+					delta_delta);
+		}
 	}
 
 	timekeeping_update(tk, TK_MIRROR);
-- 
1.9.1



  reply	other threads:[~2015-03-09  6:30 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-09  6:27 [PATCH v5 1/4] time: Add needed macros for timekeeping_inject_sleeptime64() Xunlei Pang
2015-03-09  6:27 ` Xunlei Pang [this message]
2015-03-18 17:17   ` [PATCH v5 2/4] time: Fix a bug in timekeeping_suspend() with no persistent clock John Stultz
2015-03-09  6:27 ` [PATCH v5 3/4] time: rtc: Don't bother into rtc_resume() for the nonstop clocksource Xunlei Pang
2015-03-09  6:27 ` [PATCH v5 4/4] rtc: Remove redundant rtc_valid_tm() from rtc_resume() Xunlei Pang
2015-03-18 17:26   ` John Stultz
2015-03-18 17:25 ` [PATCH v5 1/4] time: Add needed macros for timekeeping_inject_sleeptime64() John Stultz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1425882471-5591-2-git-send-email-xlpang@126.com \
    --to=xlpang@126.com \
    --cc=a.zummo@towertech.it \
    --cc=arnd.bergmann@linaro.org \
    --cc=john.stultz@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pang.xunlei@linaro.org \
    --cc=peterz@infradead.org \
    --cc=rtc-linux@googlegroups.com \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.