From: Bradley Morgan <include@grrlz.net>
To: akpm@linux-foundation.org
Cc: pmladek@suse.com, feng.tang@linux.alibaba.com, tglx@kernel.org,
peterz@infradead.org, rostedt@goodmis.org,
linux-kernel@vger.kernel.org, include@grrlz.net,
Sashiko <sashiko-bot@kernel.org>
Subject: [PATCH v2] panic: allow force_cpu redirect from an NMI
Date: Wed, 8 Jul 2026 16:43:12 +0000 [thread overview]
Message-ID: <20260708164312.19044-1-include@grrlz.net> (raw)
nmi_panic() calls panic_try_start() before panic(), so it claims
panic_cpu first. When the panic then reaches panic_try_force_cpu(),
panic_in_progress() 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.
smp_call_function_single_async() is safe from NMI context, so move
the redirect first. nmi_panic() now calls panic_try_force_cpu()
before panic_try_start(), and only claims panic_cpu when no redirect
is done. The requested CPU then claims panic_cpu itself.
Also use panic_on_other_cpu() in place of the open coded check and
return true to stop directly.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260707183253.9793-1-include@grrlz.net
Signed-off-by: Bradley Morgan <include@grrlz.net>
---
kernel/panic.c | 38 ++++++++++++++++----------------------
1 file changed, 16 insertions(+), 22 deletions(-)
Changes since v1:
- Dropped the atomic_set panic_cpu hand off, it was racy.
- Restructured nmi_panic() to call panic_try_force_cpu() first.
- Used panic_on_other_cpu() instead of an open coded check.
- panic_try_force_cpu() now takes a formatted message string.
diff --git a/kernel/panic.c b/kernel/panic.c
index ebdc46af6aa9..b039bb6f1d19 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -364,8 +364,7 @@ int __weak panic_smp_redirect_cpu(int target_cpu, void *msg)
/**
* panic_try_force_cpu - Redirect panic to a specific CPU for crash kernel
- * @fmt: panic message format string
- * @args: arguments for format string
+ * @msg: already formatted panic message
*
* Some platforms require panic handling to occur on a specific CPU
* for the crash kernel to function correctly. This function redirects
@@ -374,12 +373,10 @@ int __weak panic_smp_redirect_cpu(int target_cpu, void *msg)
* Returns false if panic should proceed on current CPU.
* Returns true if panic was redirected.
*/
-__printf(1, 0)
-static bool panic_try_force_cpu(const char *fmt, va_list args)
+static bool panic_try_force_cpu(const char *msg)
{
int this_cpu = raw_smp_processor_id();
int old_cpu = PANIC_CPU_INVALID;
- const char *msg;
/* Feature not enabled via boot parameter */
if (panic_force_cpu < 0)
@@ -396,9 +393,9 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
return false;
}
- /* Another panic already in progress */
- if (panic_in_progress())
- return false;
+ /* Stop this CPU when the panic is already proceeding elsewhere. */
+ if (panic_on_other_cpu())
+ return true;
/*
* Only one CPU can do the redirection. Others should go
@@ -412,12 +409,7 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
* fall back to static message for early boot panics or allocation failure.
*/
if (panic_force_buf) {
- va_list ap;
-
- /* Do not consume args, the caller reuses it if we fail */
- va_copy(ap, args);
- vsnprintf(panic_force_buf, PANIC_MSG_BUFSZ, fmt, ap);
- va_end(ap);
+ strscpy(panic_force_buf, msg, PANIC_MSG_BUFSZ);
msg = panic_force_buf;
} else {
msg = "Redirected panic (buffer unavailable)";
@@ -447,8 +439,7 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
return true;
}
#else
-__printf(1, 0)
-static inline bool panic_try_force_cpu(const char *fmt, va_list args)
+static inline bool panic_try_force_cpu(const char *msg)
{
return false;
}
@@ -515,7 +506,9 @@ EXPORT_SYMBOL(panic_on_other_cpu);
*/
void nmi_panic(struct pt_regs *regs, const char *msg)
{
- if (panic_try_start())
+ if (panic_try_force_cpu(msg))
+ nmi_panic_self_stop(regs);
+ else if (panic_try_start())
panic("%s", msg);
else if (panic_on_other_cpu())
nmi_panic_self_stop(regs);
@@ -609,8 +602,13 @@ void vpanic(const char *fmt, va_list args)
local_irq_disable();
preempt_disable_notrace();
+ /* Format the message once; reused for the log and any redirect IPI. */
+ len = vscnprintf(buf, sizeof(buf), fmt, args);
+ if (len && buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+
/* Redirect panic to target CPU if configured via panic_force_cpu=. */
- if (panic_try_force_cpu(fmt, args)) {
+ if (panic_try_force_cpu(buf)) {
/*
* Mark ourselves offline so panic_other_cpus_shutdown() won't wait
* for us on architectures that check num_online_cpus().
@@ -641,10 +639,6 @@ void vpanic(const char *fmt, va_list args)
console_verbose();
bust_spinlocks(1);
- len = vscnprintf(buf, sizeof(buf), fmt, args);
-
- if (len && buf[len - 1] == '\n')
- buf[len - 1] = '\0';
pr_emerg("Kernel panic - not syncing: %s\n", buf);
/*
--
2.53.0
reply other threads:[~2026-07-08 16:43 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260708164312.19044-1-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=peterz@infradead.org \
--cc=pmladek@suse.com \
--cc=rostedt@goodmis.org \
--cc=sashiko-bot@kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox