// SPDX-License-Identifier: GPL-2.0-only/* * linux/kernel/panic.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * This function is used through-out the kernel (including mm and fs) * to indicate a major problem. */#include <linux/debug_locks.h>#include <linux/sched/debug.h>#include <linux/interrupt.h>#include <linux/kgdb.h>#include <linux/kmsg_dump.h>#include <linux/kallsyms.h>#include <linux/notifier.h>#include <linux/vt_kern.h>#include <linux/module.h>#include <linux/random.h>#include <linux/ftrace.h>#include <linux/reboot.h>#include <linux/delay.h>#include <linux/kexec.h>#include <linux/panic_notifier.h>#include <linux/sched.h>#include <linux/string_helpers.h>#include <linux/sysrq.h>#include <linux/init.h>#include <linux/nmi.h>#include <linux/console.h>#include <linux/bug.h>#include <linux/ratelimit.h>#include <linux/debugfs.h>#include <linux/sysfs.h>#include <linux/context_tracking.h>#include <linux/seq_buf.h>#include <linux/sys_info.h>#include <trace/events/error_report.h>#include <asm/sections.h> #define PANIC_TIMER_STEP 100#define PANIC_BLINK_SPD 18#define PANIC_MSG_BUFSZ 1024 #ifdef CONFIG_SMP/* * Should we dump all CPUs backtraces in an oops event? * Defaults to 0, can be changed via sysctl. */static unsigned int __read_mostly sysctl_oops_all_cpu_backtrace;#else#define sysctl_oops_all_cpu_backtrace 0#endif /* CONFIG_SMP */ int panic_on_oops = IS_ENABLED(CONFIG_PANIC_ON_OOPS);static unsigned long tainted_mask = IS_ENABLED(CONFIG_RANDSTRUCT) ? (1 << TAINT_RANDSTRUCT) : 0;static int pause_on_oops;static int pause_on_oops_flag;static DEFINE_SPINLOCK(pause_on_oops_lock);bool crash_kexec_post_notifiers;int panic_on_warn __read_mostly;unsigned long panic_on_taint;bool panic_on_taint_nousertaint = false;static unsigned int warn_limit __read_mostly;static bool panic_console_replay; bool panic_triggering_all_cpu_backtrace;static bool panic_this_cpu_backtrace_printed; int panic_timeout = CONFIG_PANIC_TIMEOUT;EXPORT_SYMBOL_GPL(panic_timeout); unsigned long panic_print; static int panic_force_cpu = -1; ATOMIC_NOTIFIER_HEAD(panic_notifier_list); EXPORT_SYMBOL(panic_notifier_list); static void panic_print_deprecated(void){ pr_info_once("Kernel: The 'panic_print' parameter is now deprecated. Please use 'panic_sys_info' and 'panic_console_replay' instead.\n");} #ifdef CONFIG_SYSCTL /* * Taint values can only be increased * This means we can safely use a temporary. */static int proc_taint(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos){ struct ctl_table t; unsigned long tmptaint = get_taint(); int err; if (write && !capable(CAP_SYS_ADMIN)) return -EPERM; t = *table; t.data = &tmptaint; err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos); if (err < 0) return err; if (write) { int i; /* * If we are relying on panic_on_taint not producing * false positives due to userspace input, bail out * before setting the requested taint flags. */ if (panic_on_taint_nousertaint && (tmptaint & panic_on_taint)) return -EINVAL; /* * Poor man's atomic or. Not worth adding a primitive * to everyone's atomic.h for this */ for (i = 0; i < TAINT_FLAGS_COUNT; i++) if ((1UL << i) & tmptaint) add_taint(i, LOCKDEP_STILL_OK); } return err;} static int sysctl_panic_print_handler(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos){ if (write) panic_print_deprecated(); return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);} static const struct ctl_table kern_panic_table[] = {#ifdef CONFIG_SMP { .procname = "oops_all_cpu_backtrace", .data = &sysctl_oops_all_cpu_backtrace, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, },#endif { .procname = "tainted", .maxlen = sizeof(long), .mode = 0644, .proc_handler = proc_taint, }, { .procname = "panic", .data = &panic_timeout, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "panic_on_oops", .data = &panic_on_oops, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "panic_print", .data = &panic_print, .maxlen = sizeof(unsigned long), .mode = 0644, .proc_handler = sysctl_panic_print_handler, }, { .procname = "panic_on_warn", .data = &panic_on_warn, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, { .procname = "warn_limit", .data = &warn_limit, .maxlen = sizeof(warn_limit), .mode = 0644, .proc_handler = proc_douintvec, },#if (defined(CONFIG_X86_32) || defined(CONFIG_PARISC)) && \ defined(CONFIG_DEBUG_STACKOVERFLOW) { .procname = "panic_on_stackoverflow", .data = &sysctl_panic_on_stackoverflow, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, },#endif { .procname = "panic_sys_info", .data = &panic_print, .maxlen = sizeof(panic_print), .mode = 0644, .proc_handler = sysctl_sys_info_handler, },}; static __init int kernel_panic_sysctls_init(void){ register_sysctl_init("kernel", kern_panic_table); return 0;}late_initcall(kernel_panic_sysctls_init);#endif /* The format is "panic_sys_info=tasks,mem,locks,ftrace,..." */static int __init setup_panic_sys_info(char *buf){ /* There is no risk of race in kernel boot phase */ panic_print = sys_info_parse_param(buf); return 1;}__setup("panic_sys_info=", setup_panic_sys_info); static atomic_t warn_count = ATOMIC_INIT(0); #ifdef CONFIG_SYSFSstatic ssize_t warn_count_show(struct kobject *kobj, struct kobj_attribute *attr, char *page){ return sysfs_emit(page, "%d\n", atomic_read(&warn_count));} static struct kobj_attribute warn_count_attr = __ATTR_RO(warn_count); static __init int kernel_panic_sysfs_init(void){ sysfs_add_file_to_group(kernel_kobj, &warn_count_attr.attr, NULL); return 0;}late_initcall(kernel_panic_sysfs_init);#endif static long no_blink(int state){ return 0;} /* Returns how long it waited in ms */long (*panic_blink)(int state);EXPORT_SYMBOL(panic_blink); /* * Stop ourself in panic -- architecture code may override this */void __weak __noreturn panic_smp_self_stop(void){ while (1) cpu_relax();} /* * Stop ourselves in NMI context if another CPU has already panicked. Arch code * may override this to prepare for crash dumping, e.g. save regs info. */void __weak __noreturn nmi_panic_self_stop(struct pt_regs *regs){ panic_smp_self_stop();} /* * Stop other CPUs in panic. Architecture dependent code may override this * with more suitable version. For example, if the architecture supports * crash dump, it should save registers of each stopped CPU and disable * per-CPU features such as virtualization extensions. */void __weak crash_smp_send_stop(void){ static int cpus_stopped; /* * This function can be called twice in panic path, but obviously * we execute this only once. */ if (cpus_stopped) return; /* * Note smp_send_stop is the usual smp shutdown function, which * unfortunately means it may not be hardened to work in a panic * situation. */ smp_send_stop(); cpus_stopped = 1;} 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 int __init panic_force_cpu_setup(char *str){ int cpu; if (!str) return -EINVAL; if (kstrtoint(str, 0, &cpu) || cpu < 0 || cpu >= nr_cpu_ids) { pr_warn("panic_force_cpu: invalid value '%s'\n", str); return -EINVAL; } panic_force_cpu = cpu; return 0;}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);} /** * panic_smp_redirect_cpu - Redirect panic to target CPU * @target_cpu: CPU that should handle the panic * @msg: formatted panic message * * Default implementation uses IPI. Architectures with NMI support * can override this for more reliable delivery. * * Return: 0 on success, negative errno on failure */int __weak panic_smp_redirect_cpu(int target_cpu, void *msg){ static call_single_data_t panic_csd; panic_csd.func = do_panic_on_target_cpu; panic_csd.info = msg; return smp_call_function_single_async(target_cpu, &panic_csd);} /** * panic_try_force_cpu - Redirect panic to a specific CPU for crash kernel * @fmt: panic message format string * @args: arguments for format string * * Some platforms require panic handling to occur on a specific CPU * 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. */__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; /* Feature not enabled via boot parameter */ if (panic_force_cpu < 0) return false; /* Already on target CPU - proceed normally */ if (this_cpu == panic_force_cpu) return false; /* Target CPU is offline, can't redirect */ if (!cpu_online(panic_force_cpu)) { pr_warn("panic: target CPU %d is offline, continuing on CPU %d\n", panic_force_cpu, this_cpu); return false; } /* Another panic already in progress */ if (panic_in_progress()) return false; /* * Only one CPU can do the redirect. Use atomic cmpxchg to ensure * we don't race with another CPU also trying to redirect. */ if (!atomic_try_cmpxchg(&panic_redirect_cpu, &old_cpu, this_cpu)) return false; /* * Use dynamically allocated buffer if available, otherwise * fall back to static message for early boot panics or allocation failure. */ if (panic_force_buf) { vsnprintf(panic_force_buf, PANIC_MSG_BUFSZ, fmt, args); msg = panic_force_buf; } else { msg = "Redirected panic (buffer unavailable)"; } console_verbose(); bust_spinlocks(1); pr_emerg("panic: Redirecting from CPU %d to CPU %d for crash kernel.\n", this_cpu, panic_force_cpu); /* Dump original CPU before redirecting */ if (!test_taint(TAINT_DIE) && oops_in_progress <= 1 && IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE)) { dump_stack(); } if (panic_smp_redirect_cpu(panic_force_cpu, (void *)msg) != 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); return false; } /* IPI/NMI sent, this CPU should stop */ return true;}#else__printf(1, 0)static inline bool panic_try_force_cpu(const char *fmt, va_list args){ return false;}#endif /* CONFIG_SMP && CONFIG_CRASH_DUMP */ bool panic_try_start(void){ int old_cpu, this_cpu; /* * Only one CPU is allowed to execute the crash_kexec() code as with * panic(). Otherwise parallel calls of panic() and crash_kexec() * may stop each other. To exclude them, we use panic_cpu here too. */ old_cpu = PANIC_CPU_INVALID; this_cpu = raw_smp_processor_id(); return atomic_try_cmpxchg(&panic_cpu, &old_cpu, this_cpu);}EXPORT_SYMBOL(panic_try_start); void panic_reset(void){ atomic_set(&panic_cpu, PANIC_CPU_INVALID);}EXPORT_SYMBOL(panic_reset); bool panic_in_progress(void){ return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);}EXPORT_SYMBOL(panic_in_progress); /* Return true if a panic is in progress on the current CPU. */bool panic_on_this_cpu(void){ /* * We can use raw_smp_processor_id() here because it is impossible for * the task to be migrated to the panic_cpu, or away from it. If * panic_cpu has already been set, and we're not currently executing on * that CPU, then we never will be. */ return unlikely(atomic_read(&panic_cpu) == raw_smp_processor_id());}EXPORT_SYMBOL(panic_on_this_cpu); /* * Return true if a panic is in progress on a remote CPU. * * On true, the local CPU should immediately release any printing resources * that may be needed by the panic CPU. */bool panic_on_other_cpu(void){ return (panic_in_progress() && !panic_on_this_cpu());Lines 1–500 of 1222. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * linux/kernel/panic.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * This function is used through-out the kernel (including mm and fs) * to indicate a major problem. */ #include <linux/debug_locks.h> #include <linux/sched/debug.h> #include <linux/interrupt.h> #include <linux/kgdb.h> #include <linux/kmsg_dump.h> #include <linux/kallsyms.h> #include <linux/notifier.h> #include <linux/vt_kern.h> #include <linux/module.h> #include <linux/random.h> #include <linux/ftrace.h> #include <linux/reboot.h> #include <linux/delay.h> #include <linux/kexec.h> #include <linux/panic_notifier.h> #include <linux/sched.h> #include <linux/string_helpers.h> #include <linux/sysrq.h> #include <linux/init.h> #include <linux/nmi.h> #include <linux/console.h> #include <linux/bug.h> #include <linux/ratelimit.h> #include <linux/debugfs.h> #include <linux/sysfs.h> #include <linux/context_tracking.h> #include <linux/seq_buf.h> #include <linux/sys_info.h> #include <trace/events/error_report.h> #include <asm/sections.h> #define PANIC_TIMER_STEP 100 #define PANIC_BLINK_SPD 18 #define PANIC_MSG_BUFSZ 1024 #ifdef CONFIG_SMP /* * Should we dump all CPUs backtraces in an oops event? * Defaults to 0, can be changed via sysctl. */ static unsigned int __read_mostly sysctl_oops_all_cpu_backtrace; #else #define sysctl_oops_all_cpu_backtrace 0 #endif /* CONFIG_SMP */ int panic_on_oops = IS_ENABLED(CONFIG_PANIC_ON_OOPS); static unsigned long tainted_mask = IS_ENABLED(CONFIG_RANDSTRUCT) ? (1 << TAINT_RANDSTRUCT) : 0; static int pause_on_oops; static int pause_on_oops_flag; static DEFINE_SPINLOCK(pause_on_oops_lock); bool crash_kexec_post_notifiers; int panic_on_warn __read_mostly; unsigned long panic_on_taint; bool panic_on_taint_nousertaint = false; static unsigned int warn_limit __read_mostly; static bool panic_console_replay; bool panic_triggering_all_cpu_backtrace; static bool panic_this_cpu_backtrace_printed; int panic_timeout = CONFIG_PANIC_TIMEOUT; EXPORT_SYMBOL_GPL(panic_timeout); unsigned long panic_print; static int panic_force_cpu = -1; ATOMIC_NOTIFIER_HEAD(panic_notifier_list); EXPORT_SYMBOL(panic_notifier_list); static void panic_print_deprecated(void) { pr_info_once("Kernel: The 'panic_print' parameter is now deprecated. Please use 'panic_sys_info' and 'panic_console_replay' instead.\n"); } #ifdef CONFIG_SYSCTL /* * Taint values can only be increased * This means we can safely use a temporary. */ static int proc_taint(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { struct ctl_table t; unsigned long tmptaint = get_taint(); int err; if (write && !capable(CAP_SYS_ADMIN)) return -EPERM; t = *table; t.data = &tmptaint; err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos); if (err < 0) return err; if (write) { int i; /* * If we are relying on panic_on_taint not producing * false positives due to userspace input, bail out * before setting the requested taint flags. */ if (panic_on_taint_nousertaint && (tmptaint & panic_on_taint)) return -EINVAL; /* * Poor man's atomic or. Not worth adding a primitive * to everyone's atomic.h for this */ for (i = 0; i < TAINT_FLAGS_COUNT; i++) if ((1UL << i) & tmptaint) add_taint(i, LOCKDEP_STILL_OK); } return err; } static int sysctl_panic_print_handler(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { if (write) panic_print_deprecated(); return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); } static const struct ctl_table kern_panic_table[] = { #ifdef CONFIG_SMP { .procname = "oops_all_cpu_backtrace", .data = &sysctl_oops_all_cpu_backtrace, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, #endif { .procname = "tainted", .maxlen = sizeof(long), .mode = 0644, .proc_handler = proc_taint, }, { .procname = "panic", .data = &panic_timeout, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "panic_on_oops", .data = &panic_on_oops, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { .procname = "panic_print", .data = &panic_print, .maxlen = sizeof(unsigned long), .mode = 0644, .proc_handler = sysctl_panic_print_handler, }, { .procname = "panic_on_warn", .data = &panic_on_warn, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, { .procname = "warn_limit", .data = &warn_limit, .maxlen = sizeof(warn_limit), .mode = 0644, .proc_handler = proc_douintvec, }, #if (defined(CONFIG_X86_32) || defined(CONFIG_PARISC)) && \ defined(CONFIG_DEBUG_STACKOVERFLOW) { .procname = "panic_on_stackoverflow", .data = &sysctl_panic_on_stackoverflow, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, #endif { .procname = "panic_sys_info", .data = &panic_print, .maxlen = sizeof(panic_print), .mode = 0644, .proc_handler = sysctl_sys_info_handler, }, }; static __init int kernel_panic_sysctls_init(void) { register_sysctl_init("kernel", kern_panic_table); return 0; } late_initcall(kernel_panic_sysctls_init); #endif /* The format is "panic_sys_info=tasks,mem,locks,ftrace,..." */ static int __init setup_panic_sys_info(char *buf) { /* There is no risk of race in kernel boot phase */ panic_print = sys_info_parse_param(buf); return 1; } __setup("panic_sys_info=", setup_panic_sys_info); static atomic_t warn_count = ATOMIC_INIT(0); #ifdef CONFIG_SYSFS static ssize_t warn_count_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { return sysfs_emit(page, "%d\n", atomic_read(&warn_count)); } static struct kobj_attribute warn_count_attr = __ATTR_RO(warn_count); static __init int kernel_panic_sysfs_init(void) { sysfs_add_file_to_group(kernel_kobj, &warn_count_attr.attr, NULL); return 0; } late_initcall(kernel_panic_sysfs_init); #endif static long no_blink(int state) { return 0; } /* Returns how long it waited in ms */ long (*panic_blink)(int state); EXPORT_SYMBOL(panic_blink); /* * Stop ourself in panic -- architecture code may override this */ void __weak __noreturn panic_smp_self_stop(void) { while (1) cpu_relax(); } /* * Stop ourselves in NMI context if another CPU has already panicked. Arch code * may override this to prepare for crash dumping, e.g. save regs info. */ void __weak __noreturn nmi_panic_self_stop(struct pt_regs *regs) { panic_smp_self_stop(); } /* * Stop other CPUs in panic. Architecture dependent code may override this * with more suitable version. For example, if the architecture supports * crash dump, it should save registers of each stopped CPU and disable * per-CPU features such as virtualization extensions. */ void __weak crash_smp_send_stop(void) { static int cpus_stopped; /* * This function can be called twice in panic path, but obviously * we execute this only once. */ if (cpus_stopped) return; /* * Note smp_send_stop is the usual smp shutdown function, which * unfortunately means it may not be hardened to work in a panic * situation. */ smp_send_stop(); cpus_stopped = 1; } 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 int __init panic_force_cpu_setup(char *str) { int cpu; if (!str) return -EINVAL; if (kstrtoint(str, 0, &cpu) || cpu < 0 || cpu >= nr_cpu_ids) { pr_warn("panic_force_cpu: invalid value '%s'\n", str); return -EINVAL; } panic_force_cpu = cpu; return 0; } 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); } /** * panic_smp_redirect_cpu - Redirect panic to target CPU * @target_cpu: CPU that should handle the panic * @msg: formatted panic message * * Default implementation uses IPI. Architectures with NMI support * can override this for more reliable delivery. * * Return: 0 on success, negative errno on failure */ int __weak panic_smp_redirect_cpu(int target_cpu, void *msg) { static call_single_data_t panic_csd; panic_csd.func = do_panic_on_target_cpu; panic_csd.info = msg; return smp_call_function_single_async(target_cpu, &panic_csd); } /** * panic_try_force_cpu - Redirect panic to a specific CPU for crash kernel * @fmt: panic message format string * @args: arguments for format string * * Some platforms require panic handling to occur on a specific CPU * 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. */ __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; /* Feature not enabled via boot parameter */ if (panic_force_cpu < 0) return false; /* Already on target CPU - proceed normally */ if (this_cpu == panic_force_cpu) return false; /* Target CPU is offline, can't redirect */ if (!cpu_online(panic_force_cpu)) { pr_warn("panic: target CPU %d is offline, continuing on CPU %d\n", panic_force_cpu, this_cpu); return false; } /* Another panic already in progress */ if (panic_in_progress()) return false; /* * Only one CPU can do the redirect. Use atomic cmpxchg to ensure * we don't race with another CPU also trying to redirect. */ if (!atomic_try_cmpxchg(&panic_redirect_cpu, &old_cpu, this_cpu)) return false; /* * Use dynamically allocated buffer if available, otherwise * fall back to static message for early boot panics or allocation failure. */ if (panic_force_buf) { vsnprintf(panic_force_buf, PANIC_MSG_BUFSZ, fmt, args); msg = panic_force_buf; } else { msg = "Redirected panic (buffer unavailable)"; } console_verbose(); bust_spinlocks(1); pr_emerg("panic: Redirecting from CPU %d to CPU %d for crash kernel.\n", this_cpu, panic_force_cpu); /* Dump original CPU before redirecting */ if (!test_taint(TAINT_DIE) && oops_in_progress <= 1 && IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE)) { dump_stack(); } if (panic_smp_redirect_cpu(panic_force_cpu, (void *)msg) != 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); return false; } /* IPI/NMI sent, this CPU should stop */ return true; } #else __printf(1, 0) static inline bool panic_try_force_cpu(const char *fmt, va_list args) { return false; } #endif /* CONFIG_SMP && CONFIG_CRASH_DUMP */ bool panic_try_start(void) { int old_cpu, this_cpu; /* * Only one CPU is allowed to execute the crash_kexec() code as with * panic(). Otherwise parallel calls of panic() and crash_kexec() * may stop each other. To exclude them, we use panic_cpu here too. */ old_cpu = PANIC_CPU_INVALID; this_cpu = raw_smp_processor_id(); return atomic_try_cmpxchg(&panic_cpu, &old_cpu, this_cpu); } EXPORT_SYMBOL(panic_try_start); void panic_reset(void) { atomic_set(&panic_cpu, PANIC_CPU_INVALID); } EXPORT_SYMBOL(panic_reset); bool panic_in_progress(void) { return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID); } EXPORT_SYMBOL(panic_in_progress); /* Return true if a panic is in progress on the current CPU. */ bool panic_on_this_cpu(void) { /* * We can use raw_smp_processor_id() here because it is impossible for * the task to be migrated to the panic_cpu, or away from it. If * panic_cpu has already been set, and we're not currently executing on * that CPU, then we never will be. */ return unlikely(atomic_read(&panic_cpu) == raw_smp_processor_id()); } EXPORT_SYMBOL(panic_on_this_cpu); /* * Return true if a panic is in progress on a remote CPU. * * On true, the local CPU should immediately release any printing resources * that may be needed by the panic CPU. */ bool panic_on_other_cpu(void) { return (panic_in_progress() && !panic_on_this_cpu());