* [PATCH v2] panic: allow force_cpu redirect from an NMI
@ 2026-07-08 16:43 Bradley Morgan
0 siblings, 0 replies; only message in thread
From: Bradley Morgan @ 2026-07-08 16:43 UTC (permalink / raw)
To: akpm
Cc: pmladek, feng.tang, tglx, peterz, rostedt, linux-kernel, include,
Sashiko
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
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-07-08 16:43 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-08 16:43 [PATCH v2] panic: allow force_cpu redirect from an NMI Bradley Morgan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox