From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from confino.investici.org (confino.investici.org [93.190.126.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5AB08437101 for ; Wed, 8 Jul 2026 16:43:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=93.190.126.19 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783528997; cv=none; b=j4YXOcbZulkjpFTmJPpgz1WM7xNK8e4Tz6l59ilG40zZOCKYnH0XAcxAGQCMmKrpm3JMzUZcxwJsmexhqoMq3gC0l41v6qI6rtZA15sowU0hLwODPKdxXqGZGfpSgeILTZa0O6Xj1xwKxpspppTfWjQEsbf2Tyvy4lnjeZ4nj+s= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783528997; c=relaxed/simple; bh=/or2ODfBOZ0kDQZOhWZnwWB6HZUUTVX//IG7O8+ycV8=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=H395pGZhRftjLWTP0oHAxz8YEgeso/8M/1yJabSRDBbXN3ZBXH4ibURmp3lz2g/qJgtzPr1D7puvJRVD0K0p85mbeKMluONvOB78O2PQRtRVDxHpHszmrDG5rVwptskFBYoEM6C4octYn8M0px6KBwNhD5lG0igGBwSetT5xFzk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net; spf=pass smtp.mailfrom=grrlz.net; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b=H6wEmYfz; arc=none smtp.client-ip=93.190.126.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=grrlz.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b="H6wEmYfz" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=grrlz.net; s=stigmate; t=1783528993; bh=JTsz1Rm3jW8C2FW9kQoxXjIdQaWA1+/X0AD1MHDvrV8=; h=From:To:Cc:Subject:Date:From; b=H6wEmYfzzUH4MMENEvhc/2q+bOnjCBWS4dHLlakCeY018W6zZmyCec8Ty6UApdKdr FulJTZ98UKt3O7+yrEoRVKbnbBdKrS//1caIc+83Ogg4RIJKTxOY9FNhdjOrZ8N+dr /GXuil+ix6aBW6RooJ+BVtYx9a+ztAAqRf+ImTJI= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4gwP6T2j3Kz113S; Wed, 08 Jul 2026 16:43:13 +0000 (UTC) Received: by mx1.investici.org (Postfix) id 4gwP6S5DYRz1119; Wed, 08 Jul 2026 16:43:12 +0000 (UTC) From: Bradley Morgan 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 Subject: [PATCH v2] panic: allow force_cpu redirect from an NMI Date: Wed, 8 Jul 2026 16:43:12 +0000 Message-ID: <20260708164312.19044-1-include@grrlz.net> X-Mailer: git-send-email 2.53.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 Closes: https://sashiko.dev/#/patchset/20260707183253.9793-1-include@grrlz.net Signed-off-by: Bradley Morgan --- 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