ktime_get_snapshot() provides a snapshot of the underlying clocksource
counter value and the corresponding CLOCK_MONOTONIC_RAW, CLOCK_REALTIME and
CLOCK_BOOTTIME timestamps.

There is no usage of CLOCK_REALTIME and CLOCK_BOOTTIME at the same time and
CLOCK_BOOTTIME support was just added for the ARM64 KVM tracing mechanism,
which needs CLOCK_BOOTTIME and the underlying clocksource counter value.

ktime_get_snapshot() is also not suitable for usage with CLOCK_AUX, but
that's a prerequisite to support PTP hardware timestamping for CLOCK_AUX
steering.

As a first step, rename ktime_get_snapshot() to ktime_get_snapshot_id(),
which now takes a clockid argument to select the clock which needs to be
captured. The result is stored in system_time_snapshot::sys, which will
replace the system_time_snapshot::real/boot members once all usage sites
have been converted.

ktime_get_snapshot() is a simple wrapper which hands in CLOCK_REALTIME as
clockid argument for the conversion period. That means CLOCK_REALTIME is
now captured twice, but that redunancy is only temporary.

No functional change vs. current users of ktime_get_snapshot()

Signed-off-by: Thomas Gleixner <[email protected]>
---
 include/linux/timekeeping.h |   29 ++++++++++-----
 kernel/time/timekeeping.c   |   84 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 84 insertions(+), 29 deletions(-)

--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -276,24 +276,28 @@ static inline bool ktime_get_aux_ts64(cl
 #endif
 
 /**
- * struct system_time_snapshot - simultaneous raw/real time capture with
- *                              counter value
- * @cycles:    Clocksource counter value to produce the system times
- * @real:      Realtime system time
- * @boot:      Boot time
- * @raw:       Monotonic raw system time
- * @cs_id:     Clocksource ID
+ * struct system_time_snapshot - Simultaneous time capture of 
CLOCK_MONOTONIC_RAW,
+ *                              a selected CLOCK_* and the clocksource counter 
value
+ * @cycles:            Clocksource counter value to produce the system times
+ * @sys:               The system time of the selected CLOCK ID
+ * @real:              Realtime system time
+ * @boot:              Boot time
+ * @raw:               Monotonic raw system time
+ * @cs_id:             Clocksource ID
  * @clock_was_set_seq: The sequence number of clock-was-set events
  * @cs_was_changed_seq:        The sequence number of clocksource change events
+ * @valid:             True if the snapshot is valid
  */
 struct system_time_snapshot {
        u64                     cycles;
+       ktime_t                 sys;
        ktime_t                 real;
        ktime_t                 boot;
        ktime_t                 raw;
        enum clocksource_ids    cs_id;
        unsigned int            clock_was_set_seq;
        u8                      cs_was_changed_seq;
+       u8                      valid;
 };
 
 /**
@@ -341,9 +345,16 @@ extern int get_device_system_crosststamp
                        struct system_device_crosststamp *xtstamp);
 
 /*
- * Simultaneously snapshot realtime and monotonic raw clocks
+ * Simultaneously snapshot a given clock with MONOTONIC_RAW and the underlying
+ * clocksource counter value.
  */
-extern void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot);
+extern bool ktime_get_snapshot_id(struct system_time_snapshot 
*systime_snapshot,
+                                 clockid_t clock_id);
+
+static inline void ktime_get_snapshot(struct system_time_snapshot 
*systime_snapshot)
+{
+       WARN_ON_ONCE(!ktime_get_snapshot_id(systime_snapshot, CLOCK_REALTIME));
+}
 
 /*
  * Persistent clock related interfaces
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1183,43 +1183,87 @@ noinstr time64_t __ktime_get_real_second
 }
 
 /**
- * ktime_get_snapshot - snapshots the realtime/monotonic raw clocks with 
counter
- * @systime_snapshot:  pointer to struct receiving the system time snapshot
+ * ktime_get_snapshot_id -  Simultaneously snapshot a given clock ID with
+ *                         CLOCK_MONOTONIC_RAW and the underlying
+ *                         clocksource counter value.
+ * @systime_snapshot:  Pointer to struct receiving the system time snapshot
+ * @clock_id:          The clock ID to snapshot
  */
-void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
+bool ktime_get_snapshot_id(struct system_time_snapshot *systime_snapshot, 
clockid_t clock_id)
 {
-       struct timekeeper *tk = &tk_core.timekeeper;
+       ktime_t base_raw, base_sys, offs_sys, *offs, offs_zero = 0;
+       u64 nsec_raw, nsec_sys, now;
+       struct timekeeper *tk;
+       struct tk_data *tkd;
        unsigned int seq;
-       ktime_t base_raw;
        ktime_t base_real;
        ktime_t base_boot;
-       u64 nsec_raw;
-       u64 nsec_real;
-       u64 now;
 
-       WARN_ON_ONCE(timekeeping_suspended);
+       /* Invalidate the snapshot for all failure cases */
+       systime_snapshot->valid = false;
+
+       if (WARN_ON_ONCE(timekeeping_suspended))
+               return false;
+
+       switch (clock_id) {
+       case CLOCK_REALTIME:
+               tkd = &tk_core;
+               offs = &tk_core.timekeeper.offs_real;
+               break;
+       /* Map RAW to MONOTONIC so the loop below is trivial */
+       case CLOCK_MONOTONIC_RAW:
+       case CLOCK_MONOTONIC:
+               tkd = &tk_core;
+               offs = &offs_zero;
+               break;
+       case CLOCK_BOOTTIME:
+               tkd = &tk_core;
+               offs = &tk_core.timekeeper.offs_boot;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return false;
+       }
+
+       tk = &tkd->timekeeper;
 
        do {
-               seq = read_seqcount_begin(&tk_core.seq);
+               seq = read_seqcount_begin(&tkd->seq);
+
                now = tk_clock_read(&tk->tkr_mono);
                systime_snapshot->cs_id = tk->tkr_mono.clock->id;
                systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq;
                systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq;
-               base_real = ktime_add(tk->tkr_mono.base,
-                                     tk_core.timekeeper.offs_real);
-               base_boot = ktime_add(tk->tkr_mono.base,
-                                     tk_core.timekeeper.offs_boot);
+
+               base_sys = tk->tkr_mono.base;
+               offs_sys = *offs;
                base_raw = tk->tkr_raw.base;
-               nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, now);
-               nsec_raw  = timekeeping_cycles_to_ns(&tk->tkr_raw, now);
-       } while (read_seqcount_retry(&tk_core.seq, seq));
+
+               /* Kept around until the callers are fixed up */
+               base_real = ktime_add(base_sys, tk_core.timekeeper.offs_real);
+               base_boot = ktime_add(base_sys, tk_core.timekeeper.offs_boot);
+
+               nsec_sys = timekeeping_cycles_to_ns(&tk->tkr_mono, now);
+               nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now);
+       } while (read_seqcount_retry(&tkd->seq, seq));
 
        systime_snapshot->cycles = now;
-       systime_snapshot->real = ktime_add_ns(base_real, nsec_real);
-       systime_snapshot->boot = ktime_add_ns(base_boot, nsec_real);
+       systime_snapshot->sys = ktime_add_ns(base_sys, offs_sys + nsec_sys);
+       systime_snapshot->real = ktime_add_ns(base_real, nsec_sys);
+       systime_snapshot->boot = ktime_add_ns(base_boot, nsec_sys);
        systime_snapshot->raw = ktime_add_ns(base_raw, nsec_raw);
+
+       /*
+        * Special case for PTP. Just transfer the raw time into sys,
+        * so the call sites can consistently use snap::sys.
+        */
+       if (clock_id == CLOCK_MONOTONIC_RAW)
+               systime_snapshot->sys = systime_snapshot->raw;
+       /* Tell the consumer that this snapshot is valid */
+       systime_snapshot->valid = true;
+       return true;
 }
-EXPORT_SYMBOL_GPL(ktime_get_snapshot);
+EXPORT_SYMBOL_GPL(ktime_get_snapshot_id);
 
 /* Scale base by mult/div checking for overflow */
 static int scale64_check_overflow(u64 mult, u64 div, u64 *base)


Reply via email to