[PATCH] time: use heuristic to test persistent_clock precision

From: Gabriel M. Beddingfield
Date: Fri Oct 06 2017 - 12:55:45 EST


In commit cb33217b1b25 ("time: Avoid accumulating time drift in
suspend/resume") logic was added to timekeeping_suspend() to compensate for
read_persistent_clock() having only single-second precision. However, if
the implementation is capable of returning fractional seconds then it is
better to disable this compensation because of its interaction with NTP.

This patch checks the tv_nsec field from read_persistent_clock(). If it
ever returns a non-zero value, then the compensation is disabled.

Signed-off-by: Gabriel M. Beddingfield <beddingfield@xxxxxxxxxxxx>
---
kernel/time/timekeeping.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 2cafb49aa65e..19bf462d4ce7 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1479,6 +1479,8 @@ static bool sleeptime_injected;

/* Flag for if there is a persistent clock on this platform */
static bool persistent_clock_exists;
+/* Flag for if the persistent clock supports fractional seconds */
+static bool persistent_clock_has_fractional_seconds;

/*
* timekeeping_init - Initializes the clocksource and common timekeeping values
@@ -1703,16 +1705,24 @@ int timekeeping_suspend(void)
* 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.
+ *
+ * Likewise, some systems provide only whole (truncated) seconds
+ * for the time. If we ever see a non-zero tv_nsec, then we
+ * disable the "delta_delta" compensation.
*/
- if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec)
+ if (timekeeping_suspend_time.tv_nsec) {
+ persistent_clock_exists = true;
+ persistent_clock_has_fractional_seconds = true;
+ } else if (timekeeping_suspend_time.tv_sec) {
persistent_clock_exists = true;
+ }

raw_spin_lock_irqsave(&timekeeper_lock, flags);
write_seqcount_begin(&tk_core.seq);
timekeeping_forward_now(tk);
timekeeping_suspended = 1;

- if (persistent_clock_exists) {
+ if (persistent_clock_exists && !persistent_clock_has_fractional_seconds) {
/*
* To avoid drift caused by repeated suspend/resumes,
* which each can add ~1 second drift error,
--
2.14.2.920.gcf0c67979c-goog