From: Bradley Morgan <include@grrlz.net>
To: akpm@linux-foundation.org
Cc: pmladek@suse.com, feng.tang@linux.alibaba.com,
sashiko-bot@kernel.org, stable@vger.kernel.org,
linux-kernel@vger.kernel.org, include@grrlz.net
Subject: [PATCH v4 3/3] panic: allow force_cpu redirect from an NMI
Date: Tue, 14 Jul 2026 17:31:02 +0000 [thread overview]
Message-ID: <20260714173103.11585-4-include@grrlz.net> (raw)
In-Reply-To: <20260714173103.11585-1-include@grrlz.net>
nmi_panic() calls panic_try_start() before panic(), so it claims
panic_cpu first. When the panic then reaches panic_try_force_cpu(),
the panic_in_progress() check sees panic_cpu set and returns false,
so the redirect to the requested CPU never happens. The crash kernel
runs on the CPU that took the NMI instead.
The buggy call order, on a CPU X that is not the target (target is C):
nmi_panic()
panic_try_start() wins, panic_cpu = X
panic("%s", msg)
vpanic()
panic_try_force_cpu()
panic_in_progress() true, panic_cpu is X
return false redirect bypassed
panic_try_start() already won
__crash_kexec() on X, not C
The fix is to try the redirect before claiming panic_cpu. nmi_panic()
now calls panic_try_force_cpu_fmt() first, and only calls
panic_try_start() when no redirect happens. The requested CPU then
claims panic_cpu itself when it runs panic(), so panic_cpu does not need
to be handed off.
nmi_panic() holds an already formatted string, not a va_list. Add a
variadic wrapper, panic_try_force_cpu_fmt(), so it can reach the
existing formatting guarded by the cmpxchg in panic_try_force_cpu() without
a signature change. The wrapper builds the va_list and the real
function still copies and formats under the redirect cmpxchg, so no
shared buffer is written before ownership.
The redirect sends the IPI via smp_call_function_single_async().
This is safe from NMI context: the doc on the _async variant
states it can be called with interrupts disabled, and kgdb_roundup_cpus()
already calls it from NMI/debug context (kernel/debug/debug_core.c).
The nmi_panic() body is reshaped to a goto self_stop, since panic()
is noreturn and the stop path is shared.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260708164312.19044-1-include@grrlz.net
Cc: stable@vger.kernel.org
Signed-off-by: Bradley Morgan <include@grrlz.net>
---
kernel/panic.c | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/kernel/panic.c b/kernel/panic.c
index c58c72d9f5a0..c81a5c9646e3 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -450,12 +450,32 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
/* IPI/NMI sent, this CPU should stop */
return true;
}
+
+/* For callers without a va_list, such as nmi_panic(). */
+static __printf(1, 2)
+bool panic_try_force_cpu_fmt(const char *fmt, ...)
+{
+ va_list args;
+ bool ret;
+
+ va_start(args, fmt);
+ ret = panic_try_force_cpu(fmt, args);
+ va_end(args);
+
+ return ret;
+}
#else
__printf(1, 0)
static inline bool panic_try_force_cpu(const char *fmt, va_list args)
{
return false;
}
+
+static __printf(1, 2)
+bool panic_try_force_cpu_fmt(const char *fmt, ...)
+{
+ return false;
+}
#endif /* CONFIG_SMP && CONFIG_CRASH_DUMP */
bool panic_try_start(void)
@@ -519,11 +539,20 @@ EXPORT_SYMBOL(panic_on_other_cpu);
*/
void nmi_panic(struct pt_regs *regs, const char *msg)
{
+ /* Try to redirect to the requested CPU when one is set. */
+ if (panic_try_force_cpu_fmt("%s", msg))
+ goto self_stop;
+
+ /* Try to acquire the right to proceed with the noreturn panic(). */
if (panic_try_start())
panic("%s", msg);
- if (panic_on_other_cpu())
- nmi_panic_self_stop(regs);
+ /*
+ * panic_try_start() only fails when a panic is already in progress
+ * on another CPU, in which case this CPU must stop.
+ */
+self_stop:
+ nmi_panic_self_stop(regs);
}
EXPORT_SYMBOL(nmi_panic);
--
2.53.0
prev parent reply other threads:[~2026-07-14 17:31 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 17:30 [PATCH v4 0/3] panic: fix the panic_force_cpu redirect races Bradley Morgan
2026-07-14 17:31 ` [PATCH v4 1/3] panic: fix redirect CPU race in panic_try_force_cpu() Bradley Morgan
2026-07-14 17:31 ` [PATCH v4 2/3] panic: flatten nmi_panic control flow Bradley Morgan
2026-07-14 17:31 ` Bradley Morgan [this message]
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=20260714173103.11585-4-include@grrlz.net \
--to=include@grrlz.net \
--cc=akpm@linux-foundation.org \
--cc=feng.tang@linux.alibaba.com \
--cc=linux-kernel@vger.kernel.org \
--cc=pmladek@suse.com \
--cc=sashiko-bot@kernel.org \
--cc=stable@vger.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox