[PATCH] rseq: fix hard lockup on granted time slice extension

From: Niels Pressel

Date: Sun Aug 02 2026 - 08:47:11 EST


In __exit_to_user_mode_loop, TSE eligibility is checked while
IRQs are enabled. Granting a TSE might involve rearming the
hrtimers. However, hrtimer_rearm_deferred_tif is expected to be
called with IRQs disabled (see include/linux/hrtimer_rearm.h:17).

Calling the function with IRQs enabled can lead to a hard lockup
because __hrtimer_rearm_deferred acquires a raw spinlock (without
disabling IRQs) that is also acquired in hard IRQ context within
hrtimer_run_queues.

Lockdep flags the issue when running the rseq selftests on the
7.2-rc5 release:

WARNING: ./include/linux/hrtimer_rearm.h:17 at irqentry_exit, CPU#1: slice_test

================================
WARNING: inconsistent lock state
7.2.0-rc5 #1 Tainted: G W
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
slice_test [HC0[0]:SC0[0]:HE1:SE1] takes:
ffff95b82ec5c698 (hrtimer_bases.lock){?.-.}-{2:2}, at: __hrtimer_rearm_deferred
{IN-HARDIRQ-W} state was registered at:
lock_acquire
_raw_spin_lock_irqsave
hrtimer_run_queues
update_process_times
tick_periodic
tick_handle_periodic
timer_interrupt
__handle_irq_event_percpu
handle_irq_event_percpu
handle_irq_event
handle_level_irq
__common_interrupt
common_interrupt
asm_common_interrupt
_raw_spin_unlock_irqrestore
__setup_irq
request_threaded_irq
hpet_time_init
x86_late_time_init
start_kernel
x86_64_start_reservations
x86_64_start_kernel
common_startup_64

Possible unsafe locking scenario:

CPU0
----
lock(hrtimer_bases.lock);
<Interrupt>
lock(hrtimer_bases.lock);

*** DEADLOCK ***

Call Trace:
<TASK>
dump_stack_lvl
print_usage_bug
mark_lock.part.0
__lock_acquire
lock_acquire
_raw_spin_lock
__hrtimer_rearm_deferred
irqentry_exit
asm_sysvec_apic_timer_interrupt
</TASK>

Originally, the issue was discovered because of intermittent lockups
when heavily using rseq TSEs.

Fix this potential lockup by disabling IRQs around the timer rearm function
call. Tested the fix using the rseq selftests.

Fixes: 15dd3a948855 ("hrtimer: Push reprogramming timers into the interrupt return path")
Signed-off-by: Niels Pressel <npressel@xxxxxxx>
---
include/linux/rseq_entry.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/include/linux/rseq_entry.h b/include/linux/rseq_entry.h
index ed9da6e41a2a..31ce349ed42c 100644
--- a/include/linux/rseq_entry.h
+++ b/include/linux/rseq_entry.h
@@ -233,6 +233,7 @@ static __always_inline bool __rseq_grant_slice_extension(bool work_pending)
static __always_inline bool rseq_grant_slice_extension(unsigned long ti_work, unsigned long mask)
{
if (unlikely(__rseq_grant_slice_extension(ti_work & mask))) {
+ guard(irq)();
hrtimer_rearm_deferred_tif(ti_work);
return true;
}

base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
--
2.50.1 (Apple Git-155)