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