[systemd-devel] [PATCH][Resend][RFC] core: Fix wrong timestamps in rtc-in-local time mode.

Chunhui He hchunhui at mail.ustc.edu.cn
Thu Dec 18 06:33:36 PST 2014


Hi all,

When the system is configured to read the RTC time in the local time zone,
some timestamps recorded by systemd are wrong.

This bug can be demonstrated as the following:
(RTC is in UTC+08:00)

$ last
hch      tty1                          Wed Nov 19 15:39   still logged in
reboot   system boot  3.16.0-4-amd64   Wed Nov 19 23:39 - 15:40  (-7:-59)  <-- here
...

$ systemctl show
...
FirmwareTimestampMonotonic=0
LoaderTimestampMonotonic=0
KernelTimestamp=Wed 2014-11-19 23:39:10 CST            <-- here
KernelTimestampMonotonic=0
InitRDTimestampMonotonic=0
UserspaceTimestamp=Wed 2014-11-19 23:39:13 CST
UserspaceTimestampMonotonic=2707714
FinishTimestamp=Wed 2014-11-19 15:39:25 CST            <-- here
FinishTimestampMonotonic=14463839
SecurityStartTimestamp=Wed 2014-11-19 23:39:13 CST
SecurityStartTimestampMonotonic=2710030
SecurityFinishTimestamp=Wed 2014-11-19 23:39:13 CST
SecurityFinishTimestampMonotonic=2721209
...

Note that timestamps are _inconsistent_.
(15:39 is correct, 23:39 is 15:39 +08:00)

I think this bug is introduced in commit c3a170f3d3358135a39ac6eafe66f18aef0bd67d
(systemd: record the timestamps as early as possible).

In that commit, in order to get more accurate timestamps,
some timestamps are recorded _before_ the very first call of
settimeofday(), which does a time warp in the kernel.

The following is my patch. It has been tested with the latest systemd in git repo.

Thanks!
Chunhui He

( I posted this patch last month:
http://lists.freedesktop.org/archives/systemd-devel/2014-November/025341.html )

---
 src/core/main.c        | 11 ++++++++++-
 src/shared/time-util.c | 14 ++++++++++++++
 src/shared/time-util.h |  1 +
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/core/main.c b/src/core/main.c
index 77980e3..d658867 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1312,8 +1312,17 @@ int main(int argc, char *argv[]) {
                                 r = clock_set_timezone(&min);
                                 if (r < 0)
                                         log_error_errno(r, "Failed to apply local time delta, ignoring: %m");
-                                else
+                                else {
                                         log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min);
+
+                                        /* Fix timestamps generated before the very first call. */
+                                        dual_timestamp_warp(&kernel_timestamp, min);
+                                        dual_timestamp_warp(&userspace_timestamp, min);
+                                        if(in_initrd())
+                                                dual_timestamp_warp(&initrd_timestamp, min);
+                                        dual_timestamp_warp(&security_start_timestamp, min);
+                                        dual_timestamp_warp(&security_finish_timestamp, min);
+                                }
                         } else if (!in_initrd()) {
                                 /*
                                  * Do a dummy very first call to seal the kernel's time warp magic.
diff --git a/src/shared/time-util.c b/src/shared/time-util.c
index d3404af..f323835 100644
--- a/src/shared/time-util.c
+++ b/src/shared/time-util.c
@@ -88,6 +88,20 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
         return ts;
 }
 
+dual_timestamp* dual_timestamp_warp(dual_timestamp *ts, int min) {
+        usec_t d;
+        if (min >= 0) {
+                d = min * USEC_PER_MINUTE;
+                ts->realtime =
+                        ts->realtime > d ?
+                        ts->realtime - d : 0;
+        } else {
+                d = (-min) * USEC_PER_MINUTE;
+                ts->realtime = ts->realtime + d;
+        }
+        return ts;
+}
+
 usec_t timespec_load(const struct timespec *ts) {
         assert(ts);
 
diff --git a/src/shared/time-util.h b/src/shared/time-util.h
index b55a660..8c09963 100644
--- a/src/shared/time-util.h
+++ b/src/shared/time-util.h
@@ -74,6 +74,7 @@ usec_t now(clockid_t clock);
 dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u);
+dual_timestamp* dual_timestamp_warp(dual_timestamp *ts, int min);
 
 static inline bool dual_timestamp_is_set(dual_timestamp *ts) {
         return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) ||
-- 
2.1.3




More information about the systemd-devel mailing list