From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
To: Karl Mehltretter <kmehltretter@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>,
Thomas Gleixner <tglx@kernel.org>,
Frederic Weisbecker <frederic@kernel.org>,
Clark Williams <clrkwllms@kernel.org>,
Steven Rostedt <rostedt@goodmis.org>,
Boqun Feng <boqun@kernel.org>, Lyude Paul <lyude@redhat.com>,
Joel Fernandes <joelagnelf@nvidia.com>,
Alexander Potapenko <glider@google.com>,
Marco Elver <elver@google.com>,
linux-kernel@vger.kernel.org, linux-rt-devel@lists.linux.dev
Subject: Re: [PATCH v2] softirq: Preserve interrupt context during IRQ exit
Date: Thu, 17 Sep 2026 17:21:50 +0200 [thread overview]
Message-ID: <20260917152150.dvEKJ8B3@linutronix.de> (raw)
In-Reply-To: <20260905023210.82853-1-kmehltretter@gmail.com>
On 2026-09-05 04:32:10 [+0200], Karl Mehltretter wrote:
> __irq_exit_rcu() drops HARDIRQ_OFFSET before deferred hrtimer rearm,
> entry into softirq dispatch, and timersd wakeup. The rearm, wakeup, and
> softirq entry code before softirq_handle_begin() are still on the IRQ
> return path, but in_task() reports task context.
>
> Context-sensitive code called from this window therefore sees task
> context. ftrace records normal-context flags and selects its normal
> recursion slot. KCSAN attributes IRQ-exit accesses to the interrupted
> task, while KMSAN can select and modify that task's metadata.
The breakage is limited to KCSAN & friends within the window during
transition to softirq and out. There is nothing else? Well, the timer
wake looks wrong in trace, noted.
…
> --- a/kernel/softirq.c
> +++ b/kernel/softirq.c
> @@ -481,15 +481,35 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
> }
> EXPORT_SYMBOL(__local_bh_enable_ip);
>
> -static inline void softirq_handle_begin(void)
> +static inline bool softirq_handle_begin(void)
> {
> - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
> + bool from_hardirq = in_hardirq();
> +
> + if (!from_hardirq) {
> + __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
> + return false;
> + }
> +
> + /* Replace the retained hardirq context with normal softirq context. */
/*
* This is only entered on return from interrupt. Preemption disabled
* locations remains unchanged, the context (-HARDIRQ +SOFTIRQ) is
* updated and lockdep is let known.
*/
> + __preempt_count_add((int)SOFTIRQ_OFFSET - (int)HARDIRQ_OFFSET);
The casts look odd. We need this? It is defined as long, yes, but
preempt_count accepts an int only so it will throw the upper bits away.
> + WARN_ON_ONCE(softirq_count() != SOFTIRQ_OFFSET);
I think we want to ensure that irq_count() == SOFTIRQ_OFFSET
at this point. Only the lower preemption bits may differ, everything
else should be as we expect it. softirq_count() would drop the HARDIRQ
bits.
> + lockdep_softirqs_off(_RET_IP_);
> +
> + return true;
> }
>
> -static inline void softirq_handle_end(void)
> +static inline void softirq_handle_end(bool from_hardirq)
> {
> - __local_bh_enable(SOFTIRQ_OFFSET);
> - WARN_ON_ONCE(in_interrupt());
> + if (!from_hardirq) {
> + __local_bh_enable(SOFTIRQ_OFFSET);
> + WARN_ON_ONCE(in_interrupt());
> + return;
> + }
> +
> + WARN_ON_ONCE(softirq_count() != SOFTIRQ_OFFSET);
> + lockdep_softirqs_on(_RET_IP_);
> + __preempt_count_sub((int)SOFTIRQ_OFFSET - (int)HARDIRQ_OFFSET);
> + WARN_ON_ONCE(!in_hardirq());
that is quite some WARN_ON_ONCE. We would like to see just
HARDIRQ_OFFSET at the end. Or SOFTIRQ_OFFSET before the end. One should
be enough or the math is wrong.
> }
>
> static inline void ksoftirqd_run_begin(void)
> @@ -740,6 +761,8 @@ static inline void wake_timersd(void) { }
>
> #endif
>
> +#define IRQ_EXIT_TIMERS (NMI_MASK | HARDIRQ_MASK)
> +
> static inline void __irq_exit_rcu(void)
> {
> #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED
> @@ -748,8 +771,7 @@ static inline void __irq_exit_rcu(void)
> lockdep_assert_irqs_disabled();
> #endif
> account_hardirq_exit(current);
> - preempt_count_sub(HARDIRQ_OFFSET);
> - if (!in_interrupt() && local_softirq_pending()) {
> + if (irq_count() == HARDIRQ_OFFSET && local_softirq_pending()) {
irq_enter_rcu() did preempt_count_add(HARDIRQ_OFFSET), did record
task_struct::preempt_disable_ip. Due to the split, it does not recording
the softirq handling as disabling preemption point but keeps the
original until the end. This looks like an improvement.
> /*
> * If we left hrtimers unarmed, make sure to arm them now,
> * before enabling interrupts to run softirq.
> @@ -759,9 +781,11 @@ static inline void __irq_exit_rcu(void)
> }
>
> if (IS_ENABLED(CONFIG_IRQ_FORCED_THREADING) && force_irqthreads() &&
> - local_timers_pending_force_th() && !(in_nmi() | in_hardirq()))
> + local_timers_pending_force_th() &&
> + (preempt_count() & IRQ_EXIT_TIMERS) == HARDIRQ_OFFSET)
Why is this preempt_count() instead irq_count(). Why is there
IRQ_EXIT_TIMERS? It is almost as the first check except now we would
like to ignore the additional softirq_count().
> wake_timersd();
>
> + preempt_count_sub(HARDIRQ_OFFSET);
> tick_irq_exit();
> }
>
>
> base-commit: 2af470916a208b576ac9975d221d9a378cf8ace9
Sebastian
next prev parent reply other threads:[~2026-09-17 15:21 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-05 2:32 [PATCH v2] softirq: Preserve interrupt context during IRQ exit Karl Mehltretter
2026-09-17 15:21 ` Sebastian Andrzej Siewior [this message]
2026-09-19 7:51 ` Karl Mehltretter
2026-09-21 13:50 ` Sebastian Andrzej Siewior
2026-09-23 0:16 ` Karl Mehltretter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260917152150.dvEKJ8B3@linutronix.de \
--to=bigeasy@linutronix.de \
--cc=boqun@kernel.org \
--cc=clrkwllms@kernel.org \
--cc=elver@google.com \
--cc=frederic@kernel.org \
--cc=glider@google.com \
--cc=joelagnelf@nvidia.com \
--cc=kmehltretter@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=lyude@redhat.com \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=tglx@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.