timekeeping: Provide ktime_get_snapshot_id()

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::systime, 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.

As all usage sites of struct system_time_snapshot has to be updated anyway,
rename the 'raw' member to 'monoraw' for clarity.

No functional change vs. current users of ktime_get_snapshot()

Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: David Woodhouse <dwmw@amazon.co.uk>
Tested-by: Arthur Kiyanovski <akiyano@amazon.com>
Reviewed-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20260529195556.971591633@kernel.org
This commit is contained in:
Thomas Gleixner
2026-05-29 21:59:51 +02:00
parent 7fd2df204f
commit eba302268a
2 changed files with 88 additions and 31 deletions

View File

@@ -276,24 +276,32 @@ static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { ret
#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
* @systime: The system time of the selected CLOCK ID
* @real: Realtime system time
* @boot: Boot time
* @raw: Monotonic raw system time
* @monoraw: 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 systime;
ktime_t real;
ktime_t boot;
ktime_t raw;
union {
ktime_t raw;
ktime_t monoraw;
};
enum clocksource_ids cs_id;
unsigned int clock_was_set_seq;
u8 cs_was_changed_seq;
u8 valid;
};
/**
@@ -341,9 +349,15 @@ 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 void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *systime_snapshot);
static inline void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
{
ktime_get_snapshot_id(CLOCK_REALTIME, systime_snapshot);
}
/*
* Persistent clock related interfaces

View File

@@ -1183,43 +1183,86 @@ noinstr time64_t __ktime_get_real_seconds(void)
}
/**
* 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.
* @clock_id: The clock ID to snapshot
* @systime_snapshot: Pointer to struct receiving the system time snapshot
*/
void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *systime_snapshot)
{
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;
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;
}
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->raw = ktime_add_ns(base_raw, nsec_raw);
systime_snapshot->systime = 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->monoraw = 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::systime.
*/
if (clock_id == CLOCK_MONOTONIC_RAW)
systime_snapshot->systime = systime_snapshot->monoraw;
/* Tell the consumer that this snapshot is valid */
systime_snapshot->valid = 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)