Linux real-time development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Karl Mehltretter" <kmehltretter@gmail.com>
Cc: linux-trace-kernel@vger.kernel.org,
	linux-rt-devel@lists.linux.dev, linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH v2 05/13] entry: Add the pre-counted ordinary-hardirq entry/exit contract
Date: Wed, 28 Oct 2026 03:54:42 +0000	[thread overview]
Message-ID: <sashiko-outbox-187453@kernel.org> (raw)
In-Reply-To: <20261028033127.82193-6-kmehltretter@gmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] entry: irqentry_hardirq_enter() breaks preemptirqsoff critical timing start
- [Medium] softirq: invoke_softirq() drops ksoftirqd wake flag after inline handoff
--

commit 50eb58fd97f0b74442817ebd3d3092c57116862f
Author: Karl Mehltretter <kmehltretter@gmail.com>

entry: Add the pre-counted ordinary-hardirq entry/exit contract

This commit adds staged hardirq entry and retained exit helpers so that
ordinary hardirqs can install HARDIRQ_OFFSET and lockdep hardirq state
before entry tracing, and keep them installed until all traceable exit
callbacks have completed.

> diff --git a/kernel/entry/common.c b/kernel/entry/common.c
> index 2f5229132466c..9d207c37c5707 100644
> --- a/kernel/entry/common.c
> +++ b/kernel/entry/common.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0
>  
>  #include <linux/futex.h>
> +#include <linux/hardirq.h>
>  #include <linux/highmem.h>
>  #include <linux/irq-entry-common.h>
>  #include <linux/jump_label.h>
> @@ -120,6 +121,42 @@ noinstr irqentry_state_t irqentry_enter(struct pt_regs *regs)
>  	return irqentry_enter_from_kernel_mode(regs);
>  }
>  
> +/**
> + * irqentry_hardirq_enter - Establish state for ordinary hardirq entry
> + * @regs: Pointer to the interrupted register state
> + *
> + * Attempt a staged raw hardirq-count addition before anything instrumentable
> + * can run and record whether it was applied. Then establish IRQ-disabled and
> + * hardirq lockdep state before context tracking or irqflag tracing can invoke
> + * callbacks. The caller must have distinguished an ordinary hardirq from
> + * NMI-like entry and must finish the staged attempt with
> + * irq_enter_rcu_preempt_counted().
> + *
> + * Returns: An opaque object for the matching irqentry exit operation.
> + */
> +noinstr irqentry_state_t irqentry_hardirq_enter(struct pt_regs *regs)
> +{
> +	struct irqentry_hardirq_cookie cookie;
> +	irqentry_state_t ret;
> +
> +	cookie = irqentry_hardirq_count_start();
> +
> +	if (user_mode(regs)) {
> +		ret = (irqentry_state_t) {
> +			.exit_rcu = false,
> +		};
> +		irqentry_hardirq_count_state_set(&ret, cookie);
> +
> +		__enter_from_user_mode(regs, true);
> +		rseq_note_user_irq_entry();
> +		return ret;
> +	}
> +
> +	ret = __irqentry_enter_from_kernel_mode(regs, true);
> +	irqentry_hardirq_count_state_set(&ret, cookie);
> +	return ret;
> +}

[Severity: Medium]
Does staging HARDIRQ_OFFSET in irqentry_hardirq_enter() before calling
__enter_from_user_mode() or __irqentry_enter_from_kernel_mode() prevent the
preemptirqsoff latency tracer from starting critical timing when an ordinary
hardirq interrupts user mode or preemptible kernel mode?

When trace_type has both TRACER_IRQS_OFF and TRACER_PREEMPT_OFF enabled and
an interrupt arrives while preempt_count() is 0:

1. irqentry_hardirq_enter() calls irqentry_hardirq_count_start(), which adds
HARDIRQ_OFFSET to preempt_count() while hardware interrupts are disabled.

2. __enter_from_user_mode() or __irqentry_enter_from_kernel_mode() then calls
trace_hardirqs_off_finish() -> tracer_hardirqs_off():

kernel/trace/trace_irqsoff.c:tracer_hardirqs_off() {
	if (!preempt_trace(preempt_count()) && irq_trace())
		start_critical_timing(a0, a1);
}

Because HARDIRQ_OFFSET is already present in preempt_count(),
preempt_trace(preempt_count()) evaluates to true, so tracer_hardirqs_off()
assumes preemption was already disabled before IRQs were turned off and skips
start_critical_timing().

3. Later, irq_enter_rcu_preempt_counted() calls
irqentry_hardirq_count_finish() -> preempt_latency_start(HARDIRQ_OFFSET) ->
trace_preempt_off() -> tracer_preempt_off():

kernel/trace/trace_irqsoff.c:tracer_preempt_off() {
	if (preempt_trace(preempt_count()) && !irq_trace())
		start_critical_timing(a0, a1);
}

Because hardware interrupts are disabled, irq_trace() evaluates to true, so
tracer_preempt_off() assumes tracer_hardirqs_off() already started critical
timing and also skips start_critical_timing().

As a result, neither callback starts critical timing for the hardirq and any
subsequent softirq exit processing.

> diff --git a/kernel/softirq.c b/kernel/softirq.c
> index 7fc2200392cdf..169c559832501 100644
> --- a/kernel/softirq.c
> +++ b/kernel/softirq.c

[ ... ]

> @@ -525,12 +529,12 @@ static inline void ksoftirqd_run_end(void)
>  	local_irq_enable();
>  }
>  
> -static inline bool should_wake_ksoftirqd(void)
> +static __always_inline bool should_wake_ksoftirqd(void)
>  {
>  	return true;
>  }
>  
> -static inline void invoke_softirq(void)
> +static inline bool invoke_softirq(void)
>  {
>  	if (!force_irqthreads() || !__this_cpu_read(ksoftirqd)) {
>  #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
> @@ -548,9 +552,11 @@ static inline void invoke_softirq(void)
>  		 */
>  		do_softirq_own_stack();
>  #endif
> -	} else {
> -		wakeup_softirqd();
> +		return false;
>  	}
> +
> +	wakeup_softirqd();
> +	return true;
>  }

[Severity: Medium]
When invoke_softirq() runs __do_softirq() or do_softirq_own_stack() on
!CONFIG_PREEMPT_RT, can returning false unconditionally cause
irq_exit_wake_late_softirqs() to repeat a wakeup_softirqd() call that was
already performed by handle_softirqs()?

Inside handle_softirqs(), if softirqs are re-raised during inline draining
and the loop stops because need_resched() is set, the time limit is reached,
or max_restart is exhausted, handle_softirqs() wakes ksoftirqd itself while
leaving the remaining bits set in local_softirq_pending():

kernel/softirq.c:handle_softirqs() {
	...
	pending = local_softirq_pending();
	if (pending) {
		if (time_before(jiffies, end) && !need_resched() &&
		    --max_restart)
			goto restart;

		wakeup_softirqd();
	}
	...
}

Because invoke_softirq() still returns false after __do_softirq() or
do_softirq_own_stack(), __irq_exit_rcu() does not set
IRQ_EXIT_WAKE_KSOFTIRQD in wake_flags.

When irq_exit_rcu_preempt_counted_prepare() then runs:

	wake_flags = __irq_exit_rcu(true);
	do_sub = irqentry_hardirq_exit_prepare(cookie);
	irq_exit_wake_late_softirqs(wake_flags);

irq_exit_wake_late_softirqs() sees ksoftirqd_wake_requested as false while
local_softirq_pending() is still non-zero from the earlier handoff, causing
irq_exit_wake_ksoftirqd() to call wakeup_softirqd() a second time after
irqentry_hardirq_exit_prepare() has already emitted trace_preempt_on().

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261028033127.82193-1-kmehltretter@gmail.com?part=5

  reply	other threads:[~2026-10-28  3:54 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-28  3:31 [RFC PATCH v2 00/13] entry: Classify very early hardirq entry and return-tail callbacks Karl Mehltretter
2026-10-28  3:31 ` [RFC PATCH v2 01/13] arm64: Always inline raw preempt count updates Karl Mehltretter
2026-10-28  3:31 ` [RFC PATCH v2 02/13] arm64: percpu: Annotate __kern_my_cpu_offset() as '__always_inline' Karl Mehltretter
2026-10-28  3:31 ` [RFC PATCH v2 03/13] sched: Split preempt-count bookkeeping from raw updates Karl Mehltretter
2026-10-29  9:32   ` Peter Zijlstra
2026-10-28  3:31 ` [RFC PATCH v2 04/13] lockdep: Use raw access for pinned hardirq state Karl Mehltretter
2026-10-28  3:31 ` [RFC PATCH v2 05/13] entry: Add the pre-counted ordinary-hardirq entry/exit contract Karl Mehltretter
2026-10-28  3:54   ` sashiko-bot [this message]
2026-10-28  3:31 ` [RFC PATCH v2 06/13] entry: Skip inactive IRQ-return reschedule calls Karl Mehltretter
2026-10-28  3:51   ` sashiko-bot
2026-10-28  3:31 ` [RFC PATCH v2 07/13] context_tracking: Split IRQ-exit preparation from the EQS transition Karl Mehltretter
2026-10-28  3:31 ` [RFC PATCH v2 08/13] lockdep: Prepare IRQ-on state from a hardirq return tail Karl Mehltretter
2026-10-28  3:31 ` [RFC PATCH v2 09/13] entry: Carry ordinary-hardirq provenance through kernel return Karl Mehltretter
2026-10-28  3:31 ` [RFC PATCH v2 10/13] entry: Classify ordinary hardirq return-tail work as hardirq context Karl Mehltretter
2026-10-28  3:57   ` sashiko-bot
2026-10-28  3:31 ` [RFC PATCH v2 11/13] arm64: Use the pre-counted hardirq lifecycle Karl Mehltretter
2026-10-28  3:31 ` [RFC PATCH v2 12/13] Documentation: entry: Describe " Karl Mehltretter
2026-10-28  3:31 ` [RFC PATCH v2 13/13] locking/selftest: Exercise hardirq return-tail preparation 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=sashiko-outbox-187453@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=kmehltretter@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-devel@lists.linux.dev \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox