Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

panic: add panic_force_cpu= parameter to redirect panic to a specific CPU

Some platforms require panic handling to execute on a specific CPU for
crash dump to work reliably. This can be due to firmware limitations,
interrupt routing constraints, or platform-specific requirements where
only a single CPU is able to safely enter the crash kernel.

Add the panic_force_cpu= kernel command-line parameter to redirect panic
execution to a designated CPU. When the parameter is provided, the CPU
that initially triggers panic forwards the panic context to the target CPU
via IPI, which then proceeds with the normal panic and kexec flow.

The IPI delivery is implemented as a weak function
(panic_smp_redirect_cpu) so architectures with NMI support can override it
for more reliable delivery.

If the specified CPU is invalid, offline, or a panic is already in
progress on another CPU, the redirection is skipped and panic continues on
the current CPU.

[pnina.feder@mobileye.com: fix unused variable warning]
Link: https://lkml.kernel.org/r/20260126122618.2967950-1-pnina.feder@mobileye.com
Link: https://lkml.kernel.org/r/20260122102457.1154599-1-pnina.feder@mobileye.com
Signed-off-by: Pnina Feder <pnina.feder@mobileye.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Pnina Feder and committed by
Andrew Morton
2e171ab2 f3951e93

+186 -2
+15
Documentation/admin-guide/kernel-parameters.txt
··· 4788 4788 panic_on_warn=1 panic() instead of WARN(). Useful to cause kdump 4789 4789 on a WARN(). 4790 4790 4791 + panic_force_cpu= 4792 + [KNL,SMP] Force panic handling to execute on a specific CPU. 4793 + Format: <cpu number> 4794 + Some platforms require panic handling to occur on a 4795 + specific CPU for the crash kernel to function correctly. 4796 + This can be due to firmware limitations, interrupt routing 4797 + constraints, or platform-specific requirements where only 4798 + a particular CPU can safely enter the crash kernel. 4799 + When set, panic() will redirect execution to the specified 4800 + CPU before proceeding with the normal panic and kexec flow. 4801 + If the target CPU is offline or unavailable, panic proceeds 4802 + on the current CPU. 4803 + This option should only be used for systems with the above 4804 + constraints as it might cause the panic operation to be less reliable. 4805 + 4791 4806 panic_print= Bitmask for printing system info when panic happens. 4792 4807 User can chose combination of the following bits: 4793 4808 bit 0: print all tasks info
+8
include/linux/panic.h
··· 41 41 * PANIC_CPU_INVALID means no CPU has entered panic() or crash_kexec(). 42 42 */ 43 43 extern atomic_t panic_cpu; 44 + 45 + /* 46 + * panic_redirect_cpu is used when panic is redirected to a specific CPU via 47 + * the panic_force_cpu= boot parameter. It holds the CPU number that originally 48 + * triggered the panic before redirection. A value of PANIC_CPU_INVALID means 49 + * no redirection has occurred. 50 + */ 51 + extern atomic_t panic_redirect_cpu; 44 52 #define PANIC_CPU_INVALID -1 45 53 46 54 bool panic_try_start(void);
+1
include/linux/smp.h
··· 62 62 void __noreturn panic_smp_self_stop(void); 63 63 void __noreturn nmi_panic_self_stop(struct pt_regs *regs); 64 64 void crash_smp_send_stop(void); 65 + int panic_smp_redirect_cpu(int target_cpu, void *msg); 65 66 66 67 /* 67 68 * Call a function on all processors
+162 -2
kernel/panic.c
··· 42 42 43 43 #define PANIC_TIMER_STEP 100 44 44 #define PANIC_BLINK_SPD 18 45 + #define PANIC_MSG_BUFSZ 1024 45 46 46 47 #ifdef CONFIG_SMP 47 48 /* ··· 74 73 EXPORT_SYMBOL_GPL(panic_timeout); 75 74 76 75 unsigned long panic_print; 76 + 77 + static int panic_force_cpu = -1; 77 78 78 79 ATOMIC_NOTIFIER_HEAD(panic_notifier_list); 79 80 ··· 303 300 } 304 301 305 302 atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID); 303 + atomic_t panic_redirect_cpu = ATOMIC_INIT(PANIC_CPU_INVALID); 304 + 305 + #if defined(CONFIG_SMP) && defined(CONFIG_CRASH_DUMP) 306 + static char *panic_force_buf; 307 + 308 + static int __init panic_force_cpu_setup(char *str) 309 + { 310 + int cpu; 311 + 312 + if (!str) 313 + return -EINVAL; 314 + 315 + if (kstrtoint(str, 0, &cpu) || cpu < 0 || cpu >= nr_cpu_ids) { 316 + pr_warn("panic_force_cpu: invalid value '%s'\n", str); 317 + return -EINVAL; 318 + } 319 + 320 + panic_force_cpu = cpu; 321 + return 0; 322 + } 323 + early_param("panic_force_cpu", panic_force_cpu_setup); 324 + 325 + static int __init panic_force_cpu_late_init(void) 326 + { 327 + if (panic_force_cpu < 0) 328 + return 0; 329 + 330 + panic_force_buf = kmalloc(PANIC_MSG_BUFSZ, GFP_KERNEL); 331 + 332 + return 0; 333 + } 334 + late_initcall(panic_force_cpu_late_init); 335 + 336 + static void do_panic_on_target_cpu(void *info) 337 + { 338 + panic("%s", (char *)info); 339 + } 340 + 341 + /** 342 + * panic_smp_redirect_cpu - Redirect panic to target CPU 343 + * @target_cpu: CPU that should handle the panic 344 + * @msg: formatted panic message 345 + * 346 + * Default implementation uses IPI. Architectures with NMI support 347 + * can override this for more reliable delivery. 348 + * 349 + * Return: 0 on success, negative errno on failure 350 + */ 351 + int __weak panic_smp_redirect_cpu(int target_cpu, void *msg) 352 + { 353 + static call_single_data_t panic_csd; 354 + 355 + panic_csd.func = do_panic_on_target_cpu; 356 + panic_csd.info = msg; 357 + 358 + return smp_call_function_single_async(target_cpu, &panic_csd); 359 + } 360 + 361 + /** 362 + * panic_try_force_cpu - Redirect panic to a specific CPU for crash kernel 363 + * @fmt: panic message format string 364 + * @args: arguments for format string 365 + * 366 + * Some platforms require panic handling to occur on a specific CPU 367 + * for the crash kernel to function correctly. This function redirects 368 + * panic handling to the CPU specified via the panic_force_cpu= boot parameter. 369 + * 370 + * Returns false if panic should proceed on current CPU. 371 + * Returns true if panic was redirected. 372 + */ 373 + __printf(1, 0) 374 + static bool panic_try_force_cpu(const char *fmt, va_list args) 375 + { 376 + int this_cpu = raw_smp_processor_id(); 377 + int old_cpu = PANIC_CPU_INVALID; 378 + const char *msg; 379 + 380 + /* Feature not enabled via boot parameter */ 381 + if (panic_force_cpu < 0) 382 + return false; 383 + 384 + /* Already on target CPU - proceed normally */ 385 + if (this_cpu == panic_force_cpu) 386 + return false; 387 + 388 + /* Target CPU is offline, can't redirect */ 389 + if (!cpu_online(panic_force_cpu)) { 390 + pr_warn("panic: target CPU %d is offline, continuing on CPU %d\n", 391 + panic_force_cpu, this_cpu); 392 + return false; 393 + } 394 + 395 + /* Another panic already in progress */ 396 + if (panic_in_progress()) 397 + return false; 398 + 399 + /* 400 + * Only one CPU can do the redirect. Use atomic cmpxchg to ensure 401 + * we don't race with another CPU also trying to redirect. 402 + */ 403 + if (!atomic_try_cmpxchg(&panic_redirect_cpu, &old_cpu, this_cpu)) 404 + return false; 405 + 406 + /* 407 + * Use dynamically allocated buffer if available, otherwise 408 + * fall back to static message for early boot panics or allocation failure. 409 + */ 410 + if (panic_force_buf) { 411 + vsnprintf(panic_force_buf, PANIC_MSG_BUFSZ, fmt, args); 412 + msg = panic_force_buf; 413 + } else { 414 + msg = "Redirected panic (buffer unavailable)"; 415 + } 416 + 417 + console_verbose(); 418 + bust_spinlocks(1); 419 + 420 + pr_emerg("panic: Redirecting from CPU %d to CPU %d for crash kernel.\n", 421 + this_cpu, panic_force_cpu); 422 + 423 + /* Dump original CPU before redirecting */ 424 + if (!test_taint(TAINT_DIE) && 425 + oops_in_progress <= 1 && 426 + IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE)) { 427 + dump_stack(); 428 + } 429 + 430 + if (panic_smp_redirect_cpu(panic_force_cpu, (void *)msg) != 0) { 431 + atomic_set(&panic_redirect_cpu, PANIC_CPU_INVALID); 432 + pr_warn("panic: failed to redirect to CPU %d, continuing on CPU %d\n", 433 + panic_force_cpu, this_cpu); 434 + return false; 435 + } 436 + 437 + /* IPI/NMI sent, this CPU should stop */ 438 + return true; 439 + } 440 + #else 441 + __printf(1, 0) 442 + static inline bool panic_try_force_cpu(const char *fmt, va_list args) 443 + { 444 + return false; 445 + } 446 + #endif /* CONFIG_SMP && CONFIG_CRASH_DUMP */ 306 447 307 448 bool panic_try_start(void) 308 449 { ··· 575 428 */ 576 429 void vpanic(const char *fmt, va_list args) 577 430 { 578 - static char buf[1024]; 431 + static char buf[PANIC_MSG_BUFSZ]; 579 432 long i, i_next = 0, len; 580 433 int state = 0; 581 434 bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers; ··· 599 452 local_irq_disable(); 600 453 preempt_disable_notrace(); 601 454 455 + /* Redirect panic to target CPU if configured via panic_force_cpu=. */ 456 + if (panic_try_force_cpu(fmt, args)) { 457 + /* 458 + * Mark ourselves offline so panic_other_cpus_shutdown() won't wait 459 + * for us on architectures that check num_online_cpus(). 460 + */ 461 + set_cpu_online(smp_processor_id(), false); 462 + panic_smp_self_stop(); 463 + } 602 464 /* 603 465 * It's possible to come here directly from a panic-assertion and 604 466 * not have preempt disabled. Some functions called from here want ··· 640 484 /* 641 485 * Avoid nested stack-dumping if a panic occurs during oops processing 642 486 */ 643 - if (test_taint(TAINT_DIE) || oops_in_progress > 1) { 487 + if (atomic_read(&panic_redirect_cpu) != PANIC_CPU_INVALID && 488 + panic_force_cpu == raw_smp_processor_id()) { 489 + pr_emerg("panic: Redirected from CPU %d, skipping stack dump.\n", 490 + atomic_read(&panic_redirect_cpu)); 491 + } else if (test_taint(TAINT_DIE) || oops_in_progress > 1) { 644 492 panic_this_cpu_backtrace_printed = true; 645 493 } else if (IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE)) { 646 494 dump_stack();