mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Merge branch 'objtool/core'
Bring in the UDB and objtool data annotations to avoid conflicts while further extending the bug exceptions. Signed-off-by: Peter Zijlstra <peterz@infradead.org>
This commit is contained in:
196
kernel/panic.c
196
kernel/panic.c
@@ -36,6 +36,7 @@
|
||||
#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>
|
||||
|
||||
@@ -52,7 +53,7 @@ static unsigned int __read_mostly sysctl_oops_all_cpu_backtrace;
|
||||
#define sysctl_oops_all_cpu_backtrace 0
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
int panic_on_oops = CONFIG_PANIC_ON_OOPS_VALUE;
|
||||
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;
|
||||
@@ -63,26 +64,25 @@ 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);
|
||||
|
||||
#define PANIC_PRINT_TASK_INFO 0x00000001
|
||||
#define PANIC_PRINT_MEM_INFO 0x00000002
|
||||
#define PANIC_PRINT_TIMER_INFO 0x00000004
|
||||
#define PANIC_PRINT_LOCK_INFO 0x00000008
|
||||
#define PANIC_PRINT_FTRACE_INFO 0x00000010
|
||||
#define PANIC_PRINT_ALL_PRINTK_MSG 0x00000020
|
||||
#define PANIC_PRINT_ALL_CPU_BT 0x00000040
|
||||
#define PANIC_PRINT_BLOCKED_TASKS 0x00000080
|
||||
unsigned long panic_print;
|
||||
|
||||
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
|
||||
|
||||
/*
|
||||
@@ -128,6 +128,13 @@ static int proc_taint(const struct ctl_table *table, int write,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sysctl_panic_print_handler(const struct ctl_table *table, int write,
|
||||
void *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
panic_print_deprecated();
|
||||
return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
|
||||
}
|
||||
|
||||
static const struct ctl_table kern_panic_table[] = {
|
||||
#ifdef CONFIG_SMP
|
||||
{
|
||||
@@ -165,7 +172,7 @@ static const struct ctl_table kern_panic_table[] = {
|
||||
.data = &panic_print,
|
||||
.maxlen = sizeof(unsigned long),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_doulongvec_minmax,
|
||||
.proc_handler = sysctl_panic_print_handler,
|
||||
},
|
||||
{
|
||||
.procname = "panic_on_warn",
|
||||
@@ -193,6 +200,13 @@ static const struct ctl_table kern_panic_table[] = {
|
||||
.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)
|
||||
@@ -203,6 +217,15 @@ static __init int kernel_panic_sysctls_init(void)
|
||||
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
|
||||
@@ -277,6 +300,59 @@ void __weak crash_smp_send_stop(void)
|
||||
|
||||
atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
|
||||
|
||||
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());
|
||||
}
|
||||
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
|
||||
@@ -285,46 +361,13 @@ atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
|
||||
*/
|
||||
void nmi_panic(struct pt_regs *regs, const char *msg)
|
||||
{
|
||||
int old_cpu, this_cpu;
|
||||
|
||||
old_cpu = PANIC_CPU_INVALID;
|
||||
this_cpu = raw_smp_processor_id();
|
||||
|
||||
/* atomic_try_cmpxchg updates old_cpu on failure */
|
||||
if (atomic_try_cmpxchg(&panic_cpu, &old_cpu, this_cpu))
|
||||
if (panic_try_start())
|
||||
panic("%s", msg);
|
||||
else if (old_cpu != this_cpu)
|
||||
else if (panic_on_other_cpu())
|
||||
nmi_panic_self_stop(regs);
|
||||
}
|
||||
EXPORT_SYMBOL(nmi_panic);
|
||||
|
||||
static void panic_print_sys_info(bool console_flush)
|
||||
{
|
||||
if (console_flush) {
|
||||
if (panic_print & PANIC_PRINT_ALL_PRINTK_MSG)
|
||||
console_flush_on_panic(CONSOLE_REPLAY_ALL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (panic_print & PANIC_PRINT_TASK_INFO)
|
||||
show_state();
|
||||
|
||||
if (panic_print & PANIC_PRINT_MEM_INFO)
|
||||
show_mem();
|
||||
|
||||
if (panic_print & PANIC_PRINT_TIMER_INFO)
|
||||
sysrq_timer_list_show();
|
||||
|
||||
if (panic_print & PANIC_PRINT_LOCK_INFO)
|
||||
debug_show_all_locks();
|
||||
|
||||
if (panic_print & PANIC_PRINT_FTRACE_INFO)
|
||||
ftrace_dump(DUMP_ALL);
|
||||
|
||||
if (panic_print & PANIC_PRINT_BLOCKED_TASKS)
|
||||
show_state_filter(TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
|
||||
void check_panic_on_warn(const char *origin)
|
||||
{
|
||||
unsigned int limit;
|
||||
@@ -338,6 +381,19 @@ void check_panic_on_warn(const char *origin)
|
||||
origin, limit);
|
||||
}
|
||||
|
||||
static void panic_trigger_all_cpu_backtrace(void)
|
||||
{
|
||||
/* Temporary allow non-panic CPUs to write their backtraces. */
|
||||
panic_triggering_all_cpu_backtrace = true;
|
||||
|
||||
if (panic_this_cpu_backtrace_printed)
|
||||
trigger_allbutcpu_cpu_backtrace(raw_smp_processor_id());
|
||||
else
|
||||
trigger_all_cpu_backtrace();
|
||||
|
||||
panic_triggering_all_cpu_backtrace = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper that triggers the NMI backtrace (if set in panic_print)
|
||||
* and then performs the secondary CPUs shutdown - we cannot have
|
||||
@@ -345,12 +401,8 @@ void check_panic_on_warn(const char *origin)
|
||||
*/
|
||||
static void panic_other_cpus_shutdown(bool crash_kexec)
|
||||
{
|
||||
if (panic_print & PANIC_PRINT_ALL_CPU_BT) {
|
||||
/* Temporary allow non-panic CPUs to write their backtraces. */
|
||||
panic_triggering_all_cpu_backtrace = true;
|
||||
trigger_all_cpu_backtrace();
|
||||
panic_triggering_all_cpu_backtrace = false;
|
||||
}
|
||||
if (panic_print & SYS_INFO_ALL_CPU_BT)
|
||||
panic_trigger_all_cpu_backtrace();
|
||||
|
||||
/*
|
||||
* Note that smp_send_stop() is the usual SMP shutdown function,
|
||||
@@ -378,7 +430,6 @@ void vpanic(const char *fmt, va_list args)
|
||||
static char buf[1024];
|
||||
long i, i_next = 0, len;
|
||||
int state = 0;
|
||||
int old_cpu, this_cpu;
|
||||
bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers;
|
||||
|
||||
if (panic_on_warn) {
|
||||
@@ -415,13 +466,10 @@ void vpanic(const char *fmt, va_list args)
|
||||
* `old_cpu == this_cpu' means we came from nmi_panic() which sets
|
||||
* panic_cpu to this CPU. In this case, this is also the 1st CPU.
|
||||
*/
|
||||
old_cpu = PANIC_CPU_INVALID;
|
||||
this_cpu = raw_smp_processor_id();
|
||||
|
||||
/* atomic_try_cmpxchg updates old_cpu on failure */
|
||||
if (atomic_try_cmpxchg(&panic_cpu, &old_cpu, this_cpu)) {
|
||||
if (panic_try_start()) {
|
||||
/* go ahead */
|
||||
} else if (old_cpu != this_cpu)
|
||||
} else if (panic_on_other_cpu())
|
||||
panic_smp_self_stop();
|
||||
|
||||
console_verbose();
|
||||
@@ -432,13 +480,15 @@ void vpanic(const char *fmt, va_list args)
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
pr_emerg("Kernel panic - not syncing: %s\n", buf);
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
/*
|
||||
* Avoid nested stack-dumping if a panic occurs during oops processing
|
||||
*/
|
||||
if (!test_taint(TAINT_DIE) && oops_in_progress <= 1)
|
||||
if (test_taint(TAINT_DIE) || oops_in_progress > 1) {
|
||||
panic_this_cpu_backtrace_printed = true;
|
||||
} else if (IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE)) {
|
||||
dump_stack();
|
||||
#endif
|
||||
panic_this_cpu_backtrace_printed = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If kgdb is enabled, give it a chance to run before we stop all
|
||||
@@ -468,7 +518,7 @@ void vpanic(const char *fmt, va_list args)
|
||||
*/
|
||||
atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
|
||||
|
||||
panic_print_sys_info(false);
|
||||
sys_info(panic_print);
|
||||
|
||||
kmsg_dump_desc(KMSG_DUMP_PANIC, buf);
|
||||
|
||||
@@ -497,7 +547,9 @@ void vpanic(const char *fmt, va_list args)
|
||||
debug_locks_off();
|
||||
console_flush_on_panic(CONSOLE_FLUSH_PENDING);
|
||||
|
||||
panic_print_sys_info(true);
|
||||
if ((panic_print & SYS_INFO_PANIC_CONSOLE_REPLAY) ||
|
||||
panic_console_replay)
|
||||
console_flush_on_panic(CONSOLE_REPLAY_ALL);
|
||||
|
||||
if (!panic_blink)
|
||||
panic_blink = no_blink;
|
||||
@@ -947,10 +999,28 @@ EXPORT_SYMBOL(__stack_chk_fail);
|
||||
#endif
|
||||
|
||||
core_param(panic, panic_timeout, int, 0644);
|
||||
core_param(panic_print, panic_print, ulong, 0644);
|
||||
core_param(pause_on_oops, pause_on_oops, int, 0644);
|
||||
core_param(panic_on_warn, panic_on_warn, int, 0644);
|
||||
core_param(crash_kexec_post_notifiers, crash_kexec_post_notifiers, bool, 0644);
|
||||
core_param(panic_console_replay, panic_console_replay, bool, 0644);
|
||||
|
||||
static int panic_print_set(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
panic_print_deprecated();
|
||||
return param_set_ulong(val, kp);
|
||||
}
|
||||
|
||||
static int panic_print_get(char *val, const struct kernel_param *kp)
|
||||
{
|
||||
panic_print_deprecated();
|
||||
return param_get_ulong(val, kp);
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops panic_print_ops = {
|
||||
.set = panic_print_set,
|
||||
.get = panic_print_get,
|
||||
};
|
||||
__core_param_cb(panic_print, &panic_print_ops, &panic_print, 0644);
|
||||
|
||||
static int __init oops_setup(char *s)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user