Re: [PATCH v5] softirq: Preserve interrupt context during IRQ exit

From: Frederic Weisbecker

Date: Tue Oct 06 2026 - 06:01:02 EST


Hi Karl,

Le Wed, Sep 30, 2026 at 09:14:32PM +0200, Karl Mehltretter a écrit :
> +static inline bool softirq_handle_begin(void)
> {
> - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
> + bool from_irq_exit = in_hardirq();
> +
> + if (!from_irq_exit) {

Is this variable necessary?

> + __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
> + return false;
> + }
> +
> + /*
> + * Only reached from irq_exit(), with HARDIRQ_OFFSET still set.
> + * Replace it with SOFTIRQ_OFFSET before handle_softirqs() enables
> + * interrupts. Use the raw operation to preserve the preemption
> + * disable location recorded by irq_enter_rcu(), and update lockdep
> + * directly.
> + */
> + __preempt_count_sub(HARDIRQ_OFFSET - SOFTIRQ_OFFSET);
> + lockdep_softirqs_off(_RET_IP_);
> + WARN_ON_ONCE(irq_count() != SOFTIRQ_OFFSET);
> +
> + return true;
> }
>
> -static inline void softirq_handle_end(void)
> +static inline void softirq_handle_end(bool from_irq_exit)
> {
> - __local_bh_enable(SOFTIRQ_OFFSET);
> - WARN_ON_ONCE(in_interrupt());
> + if (!from_irq_exit) {
> + __local_bh_enable(SOFTIRQ_OFFSET);
> + WARN_ON_ONCE(in_interrupt());
> + return;
> + }
> +
> + lockdep_softirqs_on(_RET_IP_);
> + __preempt_count_add(HARDIRQ_OFFSET - SOFTIRQ_OFFSET);
> + WARN_ON_ONCE(irq_count() != HARDIRQ_OFFSET);
> }
>
> static inline void ksoftirqd_run_begin(void)
> @@ -758,10 +788,21 @@ static inline void __irq_exit_rcu(void)
> invoke_softirq();
> }
>
> + /*
> + * Wake the timer thread even if the interrupt hit a softirq or a
> + * section with BHs disabled. Only nested interrupts and NMIs are
> + * excluded.
> + */
> if (IS_ENABLED(CONFIG_IRQ_FORCED_THREADING) && force_irqthreads() &&
> - local_timers_pending_force_th() && !(in_nmi() | in_hardirq()))
> + local_timers_pending_force_th() &&
> + (in_nmi() | hardirq_count()) == HARDIRQ_OFFSET)

NMIs shouldn't ever take this path, right?

> wake_timersd();
>
> + /*
> + * tick_irq_exit() relies on in_hardirq() being false for the
> + * outermost interrupt.
> + */
> + preempt_count_sub(HARDIRQ_OFFSET);
> tick_irq_exit();

Can we also extend the HARDIRQ_OFFSET context coverage to tick_irq_exit() ?
>From a quick look I haven't found anything that would prevent from that. You just need
to turn the "if (!in_hardirq())" test to "if hardirq_count()) == HARDIRQ_OFFSET"

Thanks.

--
Frederic Weisbecker
SUSE Labs