The Linux Kernel Mailing List
 help / color / mirror / Atom feed
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