summaryrefslogtreecommitdiff
path: root/kernel/panic.c
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-09 21:05:30 +0200
committerMark Brown <broonie@kernel.org>2026-10-09 21:05:30 +0200
commit0bc99dcffd027019fb47fa61735e5a8843dfc698 (patch)
treeb2425fe02b6b8281d181224babbe8071c4c2849e /kernel/panic.c
parentf3e80afbdf1062ea584754bb17569ee363adb267 (diff)
parent56de113da14706d6a1b28648e9ff5c261f536201 (diff)
downloadlinux-next-0bc99dcffd027019fb47fa61735e5a8843dfc698.tar.gz
linux-next-0bc99dcffd027019fb47fa61735e5a8843dfc698.zip
Merge branch 'mm-nonmm-stable' of https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Diffstat (limited to 'kernel/panic.c')
-rw-r--r--kernel/panic.c102
1 files changed, 48 insertions, 54 deletions
diff --git a/kernel/panic.c b/kernel/panic.c
index 213725b612aa..170744163fc2 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -307,7 +307,7 @@ atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
atomic_t panic_redirect_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
#if defined(CONFIG_SMP) && defined(CONFIG_CRASH_DUMP)
-static char *panic_force_buf;
+static char panic_force_buf[PANIC_MSG_BUFSZ];
static int __init panic_force_cpu_setup(char *str)
{
@@ -326,17 +326,6 @@ static int __init panic_force_cpu_setup(char *str)
}
early_param("panic_force_cpu", panic_force_cpu_setup);
-static int __init panic_force_cpu_late_init(void)
-{
- if (panic_force_cpu < 0)
- return 0;
-
- panic_force_buf = kmalloc(PANIC_MSG_BUFSZ, GFP_KERNEL);
-
- return 0;
-}
-late_initcall(panic_force_cpu_late_init);
-
static void do_panic_on_target_cpu(void *info)
{
panic("%s", (char *)info);
@@ -371,15 +360,16 @@ int __weak panic_smp_redirect_cpu(int target_cpu, void *msg)
* for the crash kernel to function correctly. This function redirects
* panic handling to the CPU specified via the panic_force_cpu= boot parameter.
*
- * Returns false if panic should proceed on current CPU.
- * Returns true if panic was redirected.
+ * Returns true when this CPU must stop: the panic was redirected or is
+ * already running on another CPU.
+ * Returns false when panic() should proceed on this CPU.
*/
__printf(1, 0)
static bool panic_try_force_cpu(const char *fmt, va_list args)
{
int this_cpu = raw_smp_processor_id();
int old_cpu = PANIC_CPU_INVALID;
- const char *msg;
+ va_list ap;
/* Feature not enabled via boot parameter */
if (panic_force_cpu < 0)
@@ -396,27 +386,27 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
return false;
}
- /* Another panic already in progress */
+ /*
+ * Don't redirect when a panic is already in progress. Stop this
+ * CPU when it's another one, proceed when it's this one.
+ */
if (panic_in_progress())
- return false;
+ return panic_on_other_cpu();
/*
- * Only one CPU can do the redirect. Use atomic cmpxchg to ensure
- * we don't race with another CPU also trying to redirect.
+ * Only one CPU can do the redirection. Others should go offline.
+ * Continue with panic() when we already tried the redirection
+ * from this CPU before, for example via nmi_panic().
*/
if (!atomic_try_cmpxchg(&panic_redirect_cpu, &old_cpu, this_cpu))
- return false;
+ return old_cpu != this_cpu;
/*
- * Use dynamically allocated buffer if available, otherwise
- * fall back to static message for early boot panics or allocation failure.
+ * Do not consume args, the caller reuses them if we fail.
*/
- if (panic_force_buf) {
- vsnprintf(panic_force_buf, PANIC_MSG_BUFSZ, fmt, args);
- msg = panic_force_buf;
- } else {
- msg = "Redirected panic (buffer unavailable)";
- }
+ va_copy(ap, args);
+ vsnprintf(panic_force_buf, PANIC_MSG_BUFSZ, fmt, ap);
+ va_end(ap);
console_verbose();
bust_spinlocks(1);
@@ -431,7 +421,7 @@ static bool panic_try_force_cpu(const char *fmt, va_list args)
dump_stack();
}
- if (panic_smp_redirect_cpu(panic_force_cpu, (void *)msg) != 0) {
+ if (panic_smp_redirect_cpu(panic_force_cpu, panic_force_buf) != 0) {
atomic_set(&panic_redirect_cpu, PANIC_CPU_INVALID);
pr_warn("panic: failed to redirect to CPU %d, continuing on CPU %d\n",
panic_force_cpu, this_cpu);
@@ -503,17 +493,35 @@ bool panic_on_other_cpu(void)
EXPORT_SYMBOL(panic_on_other_cpu);
/*
- * A variant of panic() called from NMI context. We return if we've already
- * panicked on this CPU. If another CPU already panicked, loop in
- * nmi_panic_self_stop() which can provide architecture dependent code such
- * as saving register state for crash dump.
+ * A variant of panic() called from NMI context. The panic is first
+ * redirected to the CPU requested via panic_force_cpu=, when configured.
+ * We return if we've already panicked on this CPU. If another CPU already
+ * panicked, loop in nmi_panic_self_stop() which can provide architecture
+ * dependent code for saving register state for crash dump.
*/
-void nmi_panic(struct pt_regs *regs, const char *msg)
+void nmi_panic(struct pt_regs *regs, const char *fmt, ...)
{
+ va_list args;
+
+ va_start(args, fmt);
+
+ /* Try to redirect to the requested CPU before claiming panic_cpu. */
+ if (panic_try_force_cpu(fmt, args)) {
+ /*
+ * Mark ourselves offline so panic_other_cpus_shutdown() won't
+ * wait for us on architectures that check num_online_cpus().
+ */
+ set_cpu_online(raw_smp_processor_id(), false);
+ nmi_panic_self_stop(regs);
+ }
+
if (panic_try_start())
- panic("%s", msg);
- else if (panic_on_other_cpu())
+ vpanic(fmt, args);
+
+ if (panic_on_other_cpu())
nmi_panic_self_stop(regs);
+
+ va_end(args);
}
EXPORT_SYMBOL(nmi_panic);
@@ -567,6 +575,8 @@ static void panic_other_cpus_shutdown(bool crash_kexec)
crash_smp_send_stop();
}
+void __weak arch_do_panic(void) {}
+
/**
* vpanic - halt the system
* @fmt: The text string to print
@@ -742,20 +752,9 @@ void vpanic(const char *fmt, va_list args)
reboot_mode = panic_reboot_mode;
emergency_restart();
}
-#ifdef __sparc__
- {
- extern int stop_a_enabled;
- /* Make sure the user can actually press Stop-A (L1-A) */
- stop_a_enabled = 1;
- pr_emerg("Press Stop-A (L1-A) from sun keyboard or send break\n"
- "twice on console to return to the boot prom\n");
- }
-#endif
-#if defined(CONFIG_S390)
- disabled_wait();
-#endif
pr_emerg("---[ end Kernel panic - not syncing: %s ]---\n", buf);
+ arch_do_panic();
/* Do not scroll important messages printed above */
suppress_printk = 1;
@@ -1225,14 +1224,9 @@ static int panic_print_set(const char *val, const struct kernel_param *kp)
return param_set_ulong(val, kp);
}
-static int panic_print_get(char *val, const struct kernel_param *kp)
-{
- return param_get_ulong(val, kp);
-}
-
static const struct kernel_param_ops panic_print_ops = {
.set = panic_print_set,
- .get = panic_print_get,
+ .get = param_get_ulong,
};
__core_param_cb(panic_print, &panic_print_ops, &panic_print, 0644);