[RFC PATCH v2 3/5] timers: Avoid blocking on hrtimer_cpu_base lock during Oops or panic

From: Aaron Tomlin

Date: Mon Nov 02 2026 - 21:47:43 EST


When sysrq_timer_list_show() dumps active high-resolution timers across
all online CPUs, it calls ktime_get() (which spins on tk_core.seq) and
print_active_timers() unconditionally acquires each CPU's
base->cpu_base->lock via raw_spin_lock_irqsave(). If invoked from an
Oops, NMI, or panic context while the crashing CPU or a wedged remote
CPU is inside a timekeeping write section or already holds
base->cpu_base->lock, sysrq_timer_list_show() will spin indefinitely
and prevent panic recovery or kexec from completing.

Use the NMI-safe ktime_get_mono_fast_ns() helper in
sysrq_timer_list_show() and raw_spin_trylock_irqsave() in
print_active_timers() when in_nmi(), oops_in_progress, or
panic_in_progress() is active, noting any contended lock and returning cleanly instead of
deadlocking.

Fixes: d999bd9392de ("panic: add options to print system info when panic happens")
Signed-off-by: Aaron Tomlin <atomlin@xxxxxxxxxxx>
---
kernel/time/timer_list.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 0406bf4488e9..4973650c4ae5 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -68,7 +68,15 @@ static void print_active_timers(struct seq_file *m, struct hrtimer_clock_base *b

touch_nmi_watchdog();

- raw_spin_lock_irqsave(&base->cpu_base->lock, flags);
+ if (in_nmi() || oops_in_progress || panic_in_progress()) {
+ if ((!IS_ENABLED(CONFIG_SMP) && in_nmi()) ||
+ !raw_spin_trylock_irqsave(&base->cpu_base->lock, flags)) {
+ SEQ_printf(m, " [cpu_base lock contended]\n");
+ return;
+ }
+ } else {
+ raw_spin_lock_irqsave(&base->cpu_base->lock, flags);
+ }

curr = timerqueue_linked_first(&base->active);
/*
@@ -262,7 +270,8 @@ static inline void timer_list_header(struct seq_file *m, ktime_t now)

void sysrq_timer_list_show(void)
{
- ktime_t now = ktime_get();
+ ktime_t now = (in_nmi() || oops_in_progress || panic_in_progress()) ?
+ ns_to_ktime(ktime_get_mono_fast_ns()) : ktime_get();
int cpu;

timer_list_header(NULL, now);
--
2.55.0