linux/kernel/time
Thomas Gleixner d6e152d905 clockevents: Prevent timer interrupt starvation
Calvin reported an odd NMI watchdog lockup which claims that the CPU locked
up in user space. He provided a reproducer, which sets up a timerfd based
timer and then rearms it in a loop with an absolute expiry time of 1ns.

As the expiry time is in the past, the timer ends up as the first expiring
timer in the per CPU hrtimer base and the clockevent device is programmed
with the minimum delta value. If the machine is fast enough, this ends up
in a endless loop of programming the delta value to the minimum value
defined by the clock event device, before the timer interrupt can fire,
which starves the interrupt and consequently triggers the lockup detector
because the hrtimer callback of the lockup mechanism is never invoked.

As a first step to prevent this, avoid reprogramming the clock event device
when:
     - a forced minimum delta event is pending
     - the new expiry delta is less then or equal to the minimum delta

Thanks to Calvin for providing the reproducer and to Borislav for testing
and providing data from his Zen5 machine.

The problem is not limited to Zen5, but depending on the underlying
clock event device (e.g. TSC deadline timer on Intel) and the CPU speed
not necessarily observable.

This change serves only as the last resort and further changes will be made
to prevent this scenario earlier in the call chain as far as possible.

[ tglx: Updated to restore the old behaviour vs. !force and delta <= 0 and
  	fixed up the tick-broadcast handlers as pointed out by Borislav ]

Fixes: d316c57ff6 ("[PATCH] clockevents: add core functionality")
Reported-by: Calvin Owens <calvin@wbinvd.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: Calvin Owens <calvin@wbinvd.org>
Tested-by: Borislav Petkov <bp@alien8.de>
Link: https://lore.kernel.org/lkml/acMe-QZUel-bBYUh@mozart.vkv.me/
Link: https://patch.msgid.link/20260407083247.562657657@kernel.org
2026-04-10 22:45:38 +02:00
..
alarmtimer.c alarmtimer: Fix argument order in alarm_timer_forward() 2026-03-24 23:17:14 +01:00
clockevents.c clockevents: Prevent timer interrupt starvation 2026-04-10 22:45:38 +02:00
clocksource-wdtest.c clocksource/wdtest: Print time values for short udelay(1) 2025-01-15 19:49:13 +01:00
clocksource.c clocksource: Reduce watchdog readout delay limit to prevent false positives 2026-01-21 11:33:11 +01:00
hrtimer.c clockevents: Prevent timer interrupt starvation 2026-04-10 22:45:38 +02:00
itimer.c timers/itimer: Avoid direct access to hrtimer clockbase 2025-09-09 12:27:17 +02:00
jiffies.c time/jiffies: Fix sysctl file error on configurations where USER_HZ < HZ 2026-03-04 13:48:31 +01:00
Kconfig time: Introduce auxiliary POSIX clocks 2025-06-19 14:28:22 +02:00
Makefile time: Build generic update_vsyscall() only with generic time vDSO 2025-09-04 11:23:50 +02:00
namespace.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
ntp_internal.h ntp: Rename __do_adjtimex() to ntp_adjtimex() 2025-06-19 14:28:23 +02:00
ntp.c ntp: Use ktime_get_ntp_seconds() 2025-06-19 14:28:24 +02:00
posix-clock.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
posix-cpu-timers.c hrtimer: Store time as ktime_t in restart block 2025-11-14 16:31:19 +01:00
posix-stubs.c posix-timers: Get rid of [COMPAT_]SYS_NI() uses 2023-12-20 21:30:27 -08:00
posix-timers.c compiler-context-analysis: Remove __cond_lock() function-like helper 2026-01-05 16:43:33 +01:00
posix-timers.h timekeeping: Add minimal posix-timers support for auxiliary clocks 2025-06-27 20:13:12 +02:00
sched_clock.c time/sched_clock: Use ACCESS_PRIVATE() to evaluate hrtimer::function 2026-01-13 18:08:57 +01:00
sleep_timeout.c treewide, timers: Rename from_timer() to timer_container_of() 2025-06-08 09:07:37 +02:00
test_udelay.c time: Add MODULE_DESCRIPTION() to time test modules 2024-06-03 11:18:50 +02:00
tick-broadcast-hrtimer.c time: Switch to hrtimer_setup() 2025-02-18 10:32:33 +01:00
tick-broadcast.c clockevents: Prevent timer interrupt starvation 2026-04-10 22:45:38 +02:00
tick-common.c clockevents: Prevent timer interrupt starvation 2026-04-10 22:45:38 +02:00
tick-internal.h cpufreq: ondemand: Simplify idle cputime granularity test 2026-01-28 22:24:58 +01:00
tick-legacy.c timekeeping: remove xtime_update 2020-10-30 21:57:07 +01:00
tick-oneshot.c treewide: Update email address 2026-01-11 06:09:11 -10:00
tick-sched.c clockevents: Prevent timer interrupt starvation 2026-04-10 22:45:38 +02:00
tick-sched.h tick/sched: Fix struct tick_sched doc warnings 2024-04-01 10:36:35 +02:00
time_test.c time/kunit: Document handling of negative years of is_leap() 2026-02-02 12:37:54 +01:00
time.c time/jiffies: Mark jiffies_64_to_clock_t() notrace 2026-03-11 10:33:12 +01:00
timeconst.bc
timeconv.c time: Improve performance of time64_to_tm() 2021-06-24 11:51:59 +02:00
timecounter.c time/timecounter: Inline timecounter_cyc2time() 2025-12-15 20:16:49 +01:00
timekeeping_debug.c timekeeping: Add percpu counter for tracking floor swap events 2024-10-10 10:20:46 +02:00
timekeeping_internal.h timekeeping: Provide ktime_get_ntp_seconds() 2025-06-19 14:28:23 +02:00
timekeeping.c timekeeping: Fix timex status validation for auxiliary clocks 2026-03-04 20:05:37 +01:00
timekeeping.h asm-generic: cross-architecture timer cleanup 2020-12-16 00:07:17 -08:00
timer_list.c hrtimer: Remove hrtimer_clock_base:: Get_time 2025-09-09 12:27:18 +02:00
timer_migration.c cgroup: Fixes for v7.0-rc2 2026-03-03 14:25:18 -08:00
timer_migration.h timers/migration: Rename 'online' bit to 'available' 2025-11-20 20:17:31 +01:00
timer.c cpufreq: ondemand: Simplify idle cputime granularity test 2026-01-28 22:24:58 +01:00
vsyscall.c vdso/vsyscall: Avoid slow division loop in auxiliary clock update 2025-09-03 11:55:11 +02:00