vdso: is the reduced precision of the CLOCK_AUX base intentional?
From: Zhan Xusheng
Date: Mon Aug 31 2026 - 03:21:58 EST
From: Zhan Xusheng <zhanxusheng@xxxxxxxxxx>
vdso_time_update_aux() shifts the base down to nanoseconds and back up,
while the other clocks keep it scaled:
/* kernel/time/vsyscall.c */
nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
nsec += tk->monotonic_to_aux.tv_nsec;
vdso_ts->sec += __iter_div_u64_rem(nsec, NSEC_PER_SEC, &nsec);
nsec = nsec << tk->tkr_mono.shift;
That drops the fractional nanoseconds of xtime_nsec, so the reader ends up
flooring the base and the cycle delta separately, where ktime_get_aux()
floors their sum:
base = xtime_sec * NSEC + offs_aux
syscall: base + ((delta * mult + xtime_nsec) >> shift)
vdso: base + (xtime_nsec >> shift) + ((delta * mult) >> shift)
The two agree on everything else: an auxiliary timekeeper is memset in
aux_clock_enable() and __timekeeping_inject_offset() only touches
wall_to_monotonic under timekeeper_is_core_tk(), so it stays zero and
tkr_mono.base is xtime_sec * NSEC; monotonic_to_aux is set from offs_aux
by ktime_to_timespec64() in tk_update_aux_offs().
So the difference is floor(a+b) - floor(a) - floor(b), and the vdso reads
0 or 1 ns below the syscall for the same clock. With shift 24 and a
2.5 GHz counter I get the 1 ns case on 60% of the (xtime_nsec, delta)
combinations I tried.
The scaled form the other clocks use looks like it would work here too,
and would restore the exact parity that tk_update_ktime_data() documents:
nsec = tk->tkr_mono.xtime_nsec;
nsec += (u64)tk->monotonic_to_aux.tv_nsec << tk->tkr_mono.shift;
update_vdso_time_data() already shifts wall_to_monotonic.tv_nsec that way,
and monotonic_to_aux.tv_nsec has the same range, so the width is settled.
I am not claiming a monotonicity problem: across an update the step is
floor(a+d) - floor(a) - floor(d), which is 0 or 1, never negative. It is
a standing underestimate, and clock_getres() reports 1 ns for these
clocks, so it is the full advertised granularity rather than noise.
Was the reduced precision deliberate, on the grounds that the sub-ns bits
of the base carry no meaning for an auxiliary clock? If not I can send a
patch.
Unrelated, from the dispatch next to it: __cvdso_clock_gettime_common()
does msk = 1U << clock after admitting everything up to CLOCK_AUX_LAST.
That is 23 today, but raising MAX_AUX_CLOCKS past 16 would make the shift
undefined with nothing to catch it. A BUILD_BUG_ON(CLOCK_AUX_LAST >= 32)
would pin it down.
Thanks,
Zhan Xusheng