diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-18 16:23:56 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-18 16:23:56 -0700 |
| commit | 3b4128b9f374b4219eb716f4ad8a307bc7eb3d84 (patch) | |
| tree | e9489db7a4ab524e7849fb70a3cc47a08700e1ad /include | |
| parent | b0239dd672306ad242545f793132938847f17e53 (diff) | |
| parent | 4fa377c19e111c539a530a8200996b911ceff9ff (diff) | |
Merge tag 'timers-core-2026-08-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer and timekeeping core updates from Thomas Gleixner:
- Fix a subtly inconsistency in the timekeeping code, which fails to
account for the monotonicity adjustment in ntp_error.
For small changes of the clocksource multiplicator (+/-1) which are
typically used by the NTP PLL this is hard to observe. But for larger
adjustments, e.g. caused by a direct frequency setting through
adjtimex() the one-time uncompensated offset is significant.
Cure this by adjusting ntp_error with the resulting offset so that
the discrepancy is smoothed away over time
- Make tick length calculations correct in NTP.
The timekeeping core takes the quantisation of the clocksource into
account when calculating the tick length to compensate for the
deviation of the nominal NTP_INTERVAL_LENGTH.
While timekeeping gets this right, NTP is not aware of that, which
means it operates on the nominal value and not on the actual value
which is determined by the clock source frequency. The rounding of a
coarse clocksource like the ACPI PM timer results in a +127 PPM
deviation.
Cure this by exposing the deviation to the NTP code so that it can
operate on the same data as the timekeeping core. This is purely
kernel internal. User space still sees the nominal tick lenght via
adjtimex().
- The accuracy of the NTP adjustments is fairly approximate as the code
assumes that the invocations are precisely in NTP interval frequency
ticks and the final adjustment can over and under-run.
Cure this by adjusting ntp_error by the intended skew on each tick to
achieve the desired rate.
- Handle the two competing skews of time offset and time adjustment
correctly by calculating the conflict portion between the skews and
adjusting both accordingly.
- A set of updates and improvements for the selftests
- The usual small fixes and improvements all over the place
* tag 'timers-core-2026-08-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (58 commits)
selftests: timers: nsleep-lat: Check all calls to clock_nanosleep() and clock_gettime()
selftests: timers: nsleep-lat: Reuse kselftest error numbers
selftests: timers: nsleep-lat: Explicitly list the tested clocks
selftests: timers: nsleep-lat: Use NSEC_PER_MSEC define for unreasonable latency
selftests: timers: nanosleep: Report each test separately
selftests: timers: nanosleep: Explicitly handle timer_delete() failure
selftests: timers: nanosleep: Move all single clock tests out of the loop in main()
selftests: timers: nanosleep: Reuse kselftest error numbers
selftests: timers: nanosleep: Explicitly list the tested clocks
selftests: timers: nanosleep: Drop output alignment
selftests: timers: Use clock_name() and constants from clock-helpers.h
selftests: Add clock-helpers.h
timer_list: Use ktime_t over nanoseconds
timer_list: Use standard 'long long' format placeholders
hrtimer: Add a lockdep assertion to hrtimer_update_base()
timekeeping: Use u32 for clock_was_set_seq
timekeeping: Rename clockid_aux_valid() to clockid_is_aux_clock()
hrtimer: Account nr_retries on recovered interrupt retries
timers/itimer: Zero-init old itimerval before copy to userspace
nohz: Replace dead select with choice default
...
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/hrtimer.h | 34 | ||||
| -rw-r--r-- | include/linux/hrtimer_bases.h (renamed from include/linux/hrtimer_defs.h) | 16 | ||||
| -rw-r--r-- | include/linux/hrtimer_rearm.h | 5 | ||||
| -rw-r--r-- | include/linux/posix-timers.h | 5 | ||||
| -rw-r--r-- | include/linux/posix-timers_types.h | 6 | ||||
| -rw-r--r-- | include/linux/timekeeper_internal.h | 32 | ||||
| -rw-r--r-- | include/linux/timekeeping.h | 24 | ||||
| -rw-r--r-- | include/uapi/linux/time_types.h | 2 |
8 files changed, 51 insertions, 73 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 6862dea0acc5..29072d89e5cb 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -12,7 +12,6 @@ #ifndef _LINUX_HRTIMER_H #define _LINUX_HRTIMER_H -#include <linux/hrtimer_defs.h> #include <linux/hrtimer_rearm.h> #include <linux/hrtimer_types.h> #include <linux/init.h> @@ -287,37 +286,8 @@ static inline bool hrtimer_is_queued(struct hrtimer *timer) return READ_ONCE(timer->is_queued); } -/* - * Helper function to check, whether the timer is running the callback - * function - */ -static inline int hrtimer_callback_running(struct hrtimer *timer) -{ - return timer->base->running == timer; -} - -/** - * hrtimer_update_function - Update the timer's callback function - * @timer: Timer to update - * @function: New callback function - * - * Only safe to call if the timer is not enqueued. Can be called in the callback function if the - * timer is not enqueued at the same time (see the comments above HRTIMER_STATE_ENQUEUED). - */ -static inline void hrtimer_update_function(struct hrtimer *timer, - enum hrtimer_restart (*function)(struct hrtimer *)) -{ -#ifdef CONFIG_PROVE_LOCKING - guard(raw_spinlock_irqsave)(&timer->base->cpu_base->lock); - - if (WARN_ON_ONCE(hrtimer_is_queued(timer))) - return; - - if (WARN_ON_ONCE(!function)) - return; -#endif - ACCESS_PRIVATE(timer, function) = function; -} +void hrtimer_update_function(struct hrtimer *timer, + enum hrtimer_restart (*function)(struct hrtimer *)); /* Forward a hrtimer so it expires after now: */ extern u64 diff --git a/include/linux/hrtimer_defs.h b/include/linux/hrtimer_bases.h index 52ed9e46ff13..d4c83ec5c0f8 100644 --- a/include/linux/hrtimer_defs.h +++ b/include/linux/hrtimer_bases.h @@ -1,7 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LINUX_HRTIMER_DEFS_H -#define _LINUX_HRTIMER_DEFS_H +#ifndef _LINUX_HRTIMER_BASES_H +#define _LINUX_HRTIMER_BASES_H +#include <linux/hrtimer.h> #include <linux/ktime.h> #include <linux/timerqueue.h> #include <linux/seqlock.h> @@ -83,7 +84,7 @@ struct hrtimer_cpu_base { raw_spinlock_t lock; unsigned int cpu; unsigned int active_bases; - unsigned int clock_was_set_seq; + u32 clock_was_set_seq; bool hres_active; bool deferred_rearm; bool deferred_needs_update; @@ -110,4 +111,13 @@ struct hrtimer_cpu_base { } ____cacheline_aligned; +/* + * Helper function to check, whether the timer is running the callback + * function + */ +static inline int hrtimer_callback_running(struct hrtimer *timer) +{ + return timer->base->running == timer; +} + #endif diff --git a/include/linux/hrtimer_rearm.h b/include/linux/hrtimer_rearm.h index a6f2e5d5e1c7..17a81826bd9a 100644 --- a/include/linux/hrtimer_rearm.h +++ b/include/linux/hrtimer_rearm.h @@ -2,7 +2,12 @@ #ifndef _LINUX_HRTIMER_REARM_H #define _LINUX_HRTIMER_REARM_H +#include <linux/types.h> + #ifdef CONFIG_HRTIMER_REARM_DEFERRED +#include <linux/irqflags.h> +#include <linux/lockdep.h> +#include <linux/preempt.h> #include <linux/thread_info.h> void __hrtimer_rearm_deferred(void); diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 4d3dbcef379e..9a1a0c61361c 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -37,7 +37,7 @@ static inline int clockid_to_fd(const clockid_t clk) return ~(clk >> 3); } -static inline bool clockid_aux_valid(clockid_t id) +static inline bool clockid_is_aux_clock(clockid_t id) { return IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS) && id >= CLOCK_AUX && id <= CLOCK_AUX_LAST; } @@ -47,7 +47,7 @@ static inline bool clockid_aux_valid(clockid_t id) #include <linux/signal_types.h> /** - * cpu_timer - Posix CPU timer representation for k_itimer + * struct cpu_timer - Posix CPU timer representation for k_itimer * @node: timerqueue node to queue in the task/sig * @head: timerqueue head on which this timer is queued * @pid: Pointer to target task PID @@ -174,6 +174,7 @@ static inline void posix_cputimers_init_work(void) { } * @it_sigqueue_seq: The sequence count at the point where the signal was queued * @it_sigev_notify: The notify word of sigevent struct for signal delivery * @it_interval: The interval for periodic timers + * @it_pid_type: The type of the PID * @it_signal: Pointer to the creators signal struct * @it_pid: The pid of the process/task targeted by the signal * @it_process: The task to wakeup on clock_nanosleep (CPU timers) diff --git a/include/linux/posix-timers_types.h b/include/linux/posix-timers_types.h index a4712c1008c9..b40cf352e01d 100644 --- a/include/linux/posix-timers_types.h +++ b/include/linux/posix-timers_types.h @@ -34,7 +34,7 @@ #ifdef CONFIG_POSIX_TIMERS /** - * posix_cputimer_base - Container per posix CPU clock + * struct posix_cputimer_base - Container per posix CPU clock * @nextevt: Earliest-expiration cache * @tqhead: timerqueue head for cpu_timers */ @@ -44,7 +44,7 @@ struct posix_cputimer_base { }; /** - * posix_cputimers - Container for posix CPU timer related data + * struct posix_cputimers - Container for posix CPU timer related data * @bases: Base container for posix CPU clocks * @timers_active: Timers are queued. * @expiry_active: Timer expiry is active. Used for @@ -60,7 +60,7 @@ struct posix_cputimers { }; /** - * posix_cputimers_work - Container for task work based posix CPU timer expiry + * struct posix_cputimers_work - Container for task work based posix CPU timer expiry * @work: The task work to be scheduled * @mutex: Mutex held around expiry in context of this task work * @scheduled: @work has been scheduled already, no further processing diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index 4486dfd5d0de..fe077d97b5f8 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h @@ -84,8 +84,6 @@ struct tk_read_base { * @cycle_interval: Number of clock cycles in one NTP interval * @xtime_interval: Number of clock shifted nano seconds in one NTP * interval. - * @xtime_remainder: Shifted nano seconds left over when rounding - * @cycle_interval * @raw_interval: Shifted raw nano seconds accumulated per NTP interval. * @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second * @ntp_tick: The ntp_tick_length() value currently being @@ -99,6 +97,10 @@ struct tk_read_base { * @ntp_error_shift: Shift conversion between clock shifted nano seconds and * ntp shifted nano seconds. * @ntp_err_mult: Multiplication factor for scaled math conversion + * @cs_tick_adj: Per-second adjustment handed to NTP via ntp_clear() + * accounting for the difference between the nominal + * NTP interval and the real time taken by the + * clocksource's integer @cycle_interval (upscaled). * @skip_second_overflow: Flag used to avoid updating NTP twice with same second * @tai_offset: The current UTC to TAI offset in seconds * @@ -167,7 +169,7 @@ struct timekeeper { u32 cs_ns_to_cyc_mult; u32 cs_ns_to_cyc_shift; u64 cs_ns_to_cyc_maxns; - unsigned int clock_was_set_seq; + u32 clock_was_set_seq; u8 cs_was_changed_seq; u8 clock_valid; @@ -178,7 +180,6 @@ struct timekeeper { u64 cycle_interval; u64 xtime_interval; - s64 xtime_remainder; u64 raw_interval; ktime_t next_leap_ktime; @@ -186,29 +187,10 @@ struct timekeeper { s64 ntp_error; u32 ntp_error_shift; u32 ntp_err_mult; + s64 cs_tick_adj; u32 skip_second_overflow; + s64 skew_delta; s32 tai_offset; }; -#ifdef CONFIG_GENERIC_GETTIMEOFDAY - -extern void update_vsyscall(struct timekeeper *tk); -extern void update_vsyscall_tz(void); - -#else - -static inline void update_vsyscall(struct timekeeper *tk) -{ -} -static inline void update_vsyscall_tz(void) -{ -} -#endif - -#if defined(CONFIG_GENERIC_GETTIMEOFDAY) && defined(CONFIG_POSIX_AUX_CLOCKS) -extern void vdso_time_update_aux(struct timekeeper *tk); -#else -static inline void vdso_time_update_aux(struct timekeeper *tk) { } -#endif - #endif /* _LINUX_TIMEKEEPER_INTERNAL_H */ diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 984a866d293b..efa9442aaeef 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -44,7 +44,6 @@ extern void ktime_get_ts64(struct timespec64 *ts); extern void ktime_get_real_ts64(struct timespec64 *tv); extern void ktime_get_coarse_ts64(struct timespec64 *ts); extern void ktime_get_coarse_real_ts64(struct timespec64 *ts); -extern void ktime_get_clock_ts64(clockid_t id, struct timespec64 *ts); /* Multigrain timestamp interfaces */ extern void ktime_get_coarse_real_ts64_mg(struct timespec64 *ts); @@ -268,15 +267,18 @@ extern void timekeeping_inject_sleeptime64(const struct timespec64 *delta); * Auxiliary clock interfaces */ #ifdef CONFIG_POSIX_AUX_CLOCKS -extern bool ktime_get_aux(clockid_t id, ktime_t *kt); -extern bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt); +extern bool __must_check ktime_get_aux(clockid_t id, ktime_t *kt); +extern bool __must_check ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt); #else -static inline bool ktime_get_aux(clockid_t id, ktime_t *kt) { return false; } -static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { return false; } +static inline bool __must_check ktime_get_aux(clockid_t id, ktime_t *kt) { return false; } +static inline bool __must_check ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) +{ + return false; +} #endif /** - * struct system_time_snapshot - Simultaneous time capture of CLOCK_MONOTONIC_RAW, + * struct system_time_snapshot - Simultaneous time capture of monotonic raw time, * a selected CLOCK_* and the clocksource counter value * @cycles: Clocksource counter value to produce the system times * @hw_cycles: For derived clocksources, the hardware counter value from @@ -289,6 +291,10 @@ static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { ret * @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 + * + * @monoraw is CLOCK_MONOTONIC_RAW for system time CLOCK ids. For CLOCK_AUX$N + * clock ids it's the monotonic raw time related to the AUX clock, which is + * CLOCK_MONOTONIC_RAW plus a AUX clock specific offset. */ struct system_time_snapshot { u64 cycles; @@ -297,7 +303,7 @@ struct system_time_snapshot { ktime_t monoraw; enum clocksource_ids cs_id; enum clocksource_ids hw_csid; - unsigned int clock_was_set_seq; + u32 clock_was_set_seq; u8 cs_was_changed_seq; u8 valid; }; @@ -326,6 +332,10 @@ struct system_counterval_t { * @sys_counter: Clocksource counter value simultaneous with device time * @sys_systime: System time for @clock_id * @sys_monoraw: Monotonic raw simultaneous with device time + * + * @sys_monoraw is CLOCK_MONOTONIC_RAW for system time CLOCK ids. For + * CLOCK_AUX$N clock ids it's the monotonic raw time related to the AUX clock, + * which is CLOCK_MONOTONIC_RAW plus a AUX clock specific offset. */ struct system_device_crosststamp { clockid_t clock_id; diff --git a/include/uapi/linux/time_types.h b/include/uapi/linux/time_types.h index bcc0002115d3..03a0d8aaadca 100644 --- a/include/uapi/linux/time_types.h +++ b/include/uapi/linux/time_types.h @@ -30,7 +30,7 @@ struct __kernel_old_timeval { struct __kernel_old_timespec { __kernel_old_time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ + __kernel_long_t tv_nsec; /* nanoseconds */ }; struct __kernel_old_itimerval { |
