Clock MONOTONIC timestamps are not allowing reliable correlation to other
timestamps (clock REALTIME/BOOTTIME). For post mortem analysis and other
purposes its helpful to store all of these time stamps in the printk ring
buffer entries.

Rework __ktime_get_real_fast() so it captures both MONOTONIC and REALTIME
atomically and provide an accessor which stores these plus BOOTTIME in a
new system_timestamp data structure.

Signed-off-by: Thomas Gleixner <t...@linutronix.de>
---
 include/linux/timekeeping.h |   17 ++++++++++++++++-
 kernel/time/timekeeping.c   |   36 +++++++++++++++++++++++++-----------
 2 files changed, 41 insertions(+), 12 deletions(-)

--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -146,7 +146,19 @@ extern void timekeeping_inject_sleeptime
  * PPS accessor
  */
 extern void ktime_get_raw_and_real_ts64(struct timespec64 *ts_raw,
-                                       struct timespec64 *ts_real);
+                                       struct timespec64 *ts_real);
+
+/*
+ * struct system_timestamps - Simultaneous mono/boot/real timestamps
+ * @mono:      Monotonic timestamp
+ * @boot:      Boottime timestamp
+ * @real:      Realtime timestamp
+ */
+struct system_timestamps {
+       u64             mono;
+       u64             boot;
+       u64             real;
+};
 
 /*
  * struct system_time_snapshot - simultaneous raw/real time capture with
@@ -206,6 +218,9 @@ extern int get_device_system_crosststamp
  */
 extern void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot);
 
+/* NMI safe mono/boot/realtime timestamps */
+extern void ktime_get_fast_timestamps(struct system_timestamps *ts);
+
 /*
  * Persistent clock related interfaces
  */
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -496,29 +496,29 @@ u64 notrace ktime_get_boot_fast_ns(void)
 }
 EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);
 
-
 /*
  * See comment for __ktime_get_fast_ns() vs. timestamp ordering
  */
-static __always_inline u64 __ktime_get_real_fast_ns(struct tk_fast *tkf)
+static notrace u64 __ktime_get_real_fast(struct tk_fast *tkf, u64 *mono)
 {
        struct tk_read_base *tkr;
+       u64 basem, baser, delta;
        unsigned int seq;
-       u64 now;
 
        do {
                seq = raw_read_seqcount_latch(&tkf->seq);
                tkr = tkf->base + (seq & 0x01);
-               now = ktime_to_ns(tkr->base_real);
+               basem = ktime_to_ns(tkr->base);
+               baser = ktime_to_ns(tkr->base_real);
 
-               now += timekeeping_delta_to_ns(tkr,
-                               clocksource_delta(
-                                       tk_clock_read(tkr),
-                                       tkr->cycle_last,
-                                       tkr->mask));
+               delta = timekeeping_delta_to_ns(tkr,
+                               clocksource_delta(tk_clock_read(tkr),
+                               tkr->cycle_last, tkr->mask));
        } while (read_seqcount_retry(&tkf->seq, seq));
 
-       return now;
+       if (mono)
+               *mono = basem + delta;
+       return baser + delta;
 }
 
 /**
@@ -526,11 +526,25 @@ static __always_inline u64 __ktime_get_r
  */
 u64 ktime_get_real_fast_ns(void)
 {
-       return __ktime_get_real_fast_ns(&tk_fast_mono);
+       return __ktime_get_real_fast(&tk_fast_mono, NULL);
 }
 EXPORT_SYMBOL_GPL(ktime_get_real_fast_ns);
 
 /**
+ * ktime_get_fast_timestamps: - NMI safe timestamps
+ * @ts:                Pointer to timestamp storage
+ *
+ * Stores clock monotonic, boottime and realtime time stamps
+ */
+void ktime_get_fast_timestamps(struct system_timestamps *ts)
+{
+       struct timekeeper *tk = &tk_core.timekeeper;
+
+       ts->real = __ktime_get_real_fast(&tk_fast_mono, &ts->mono);
+       ts->boot = ts->mono + ktime_to_ns(tk->offs_boot);
+}
+
+/**
  * halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource.
  * @tk: Timekeeper to snapshot.
  *


Reply via email to