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

Niels Pressel posted 1 patch 1 month, 2 weeks ago
include/linux/rseq_entry.h | 1 +
1 file changed, 1 insertion(+)
[PATCH v3] rseq: Fix hard lockup on granted time slice extension
Posted by Niels Pressel 1 month, 2 weeks ago
In __exit_to_user_mode_loop(), rseq time slice extension (TSE)
eligibility is checked while interrupts are enabled. Granting a
TSE might involve rearming the hrtimers. However,
hrtimer_rearm_deferred_tif() is expected to be called with interrupts
disabled.

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

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

Fix this potential lockup by disabling IRQs before rearming the hrtimer
when a TSE is granted.

Fixes: 15dd3a948855 ("hrtimer: Push reprogramming timers into the interrupt return path")
Signed-off-by: Niels Pressel <npressel@ethz.ch>
---
Changes in v3:
- Revert to the v1 approach of disabling IRQs around the timer rearm because
  of issues in v2 pointed out by Thomas Gleixner
- Rebased on v7.2-rc7
- Link to v2: https://lore.kernel.org/all/20260806113429.38333-1-npressel@ethz.ch/
Changes in v2:
- Move to enabling IRQS in __exit_to_user_mode_loop() after the rseq 
  TSE check
- Remove IRQ disable in __rseq_grant_slice_extension()
- Rebased on core/entry
- Link to v1: https://lore.kernel.org/all/20260802124423.51616-1-npressel@ethz.ch/

 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: db2ddb87143519e20a95aa36c60b36107b736a58
-- 
2.50.1 (Apple Git-155)