Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

softirq: Prepare for deferred hrtimer rearming

The hrtimer interrupt expires timers and at the end of the interrupt it
rearms the clockevent device for the next expiring timer.

That's obviously correct, but in the case that a expired timer sets
NEED_RESCHED the return from interrupt ends up in schedule(). If HRTICK is
enabled then schedule() will modify the hrtick timer, which causes another
reprogramming of the hardware.

That can be avoided by deferring the rearming to the return from interrupt
path and if the return results in a immediate schedule() invocation then it
can be deferred until the end of schedule(), which avoids multiple rearms
and re-evaluation of the timer wheel.

In case that the return from interrupt ends up handling softirqs before
reaching the rearm conditions in the return to user entry code functions, a
deferred rearm has to be handled before softirq handling enables interrupts
as soft interrupt handling can be long and would therefore introduce hard
to diagnose latencies to the timer interrupt.

Place the for now empty stub call right before invoking the softirq
handling routine.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163431.142854488@kernel.org

+14 -1
+14 -1
kernel/softirq.c
··· 663 663 { 664 664 __irq_enter_raw(); 665 665 666 + /* 667 + * If this is a nested interrupt that hits the exit_to_user_mode_loop 668 + * where it has enabled interrupts but before it has hit schedule() we 669 + * could have hrtimers in an undefined state. Fix it up here. 670 + */ 671 + hrtimer_rearm_deferred(); 672 + 666 673 if (tick_nohz_full_cpu(smp_processor_id()) || 667 674 (is_idle_task(current) && (irq_count() == HARDIRQ_OFFSET))) 668 675 tick_irq_enter(); ··· 726 719 #endif 727 720 account_hardirq_exit(current); 728 721 preempt_count_sub(HARDIRQ_OFFSET); 729 - if (!in_interrupt() && local_softirq_pending()) 722 + if (!in_interrupt() && local_softirq_pending()) { 723 + /* 724 + * If we left hrtimers unarmed, make sure to arm them now, 725 + * before enabling interrupts to run SoftIRQ. 726 + */ 727 + hrtimer_rearm_deferred(); 730 728 invoke_softirq(); 729 + } 731 730 732 731 if (IS_ENABLED(CONFIG_IRQ_FORCED_THREADING) && force_irqthreads() && 733 732 local_timers_pending_force_th() && !(in_nmi() | in_hardirq()))