diff options
Diffstat (limited to 'lib/nmi_backtrace.c')
-rw-r--r-- | lib/nmi_backtrace.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c index 26caf51cc238..75554754eadf 100644 --- a/lib/nmi_backtrace.c +++ b/lib/nmi_backtrace.c | |||
@@ -16,21 +16,23 @@ | |||
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/kprobes.h> | 17 | #include <linux/kprobes.h> |
18 | #include <linux/nmi.h> | 18 | #include <linux/nmi.h> |
19 | #include <linux/cpu.h> | ||
19 | 20 | ||
20 | #ifdef arch_trigger_all_cpu_backtrace | 21 | #ifdef arch_trigger_cpumask_backtrace |
21 | /* For reliability, we're prepared to waste bits here. */ | 22 | /* For reliability, we're prepared to waste bits here. */ |
22 | static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; | 23 | static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; |
23 | 24 | ||
24 | /* "in progress" flag of arch_trigger_all_cpu_backtrace */ | 25 | /* "in progress" flag of arch_trigger_cpumask_backtrace */ |
25 | static unsigned long backtrace_flag; | 26 | static unsigned long backtrace_flag; |
26 | 27 | ||
27 | /* | 28 | /* |
28 | * When raise() is called it will be is passed a pointer to the | 29 | * When raise() is called it will be passed a pointer to the |
29 | * backtrace_mask. Architectures that call nmi_cpu_backtrace() | 30 | * backtrace_mask. Architectures that call nmi_cpu_backtrace() |
30 | * directly from their raise() functions may rely on the mask | 31 | * directly from their raise() functions may rely on the mask |
31 | * they are passed being updated as a side effect of this call. | 32 | * they are passed being updated as a side effect of this call. |
32 | */ | 33 | */ |
33 | void nmi_trigger_all_cpu_backtrace(bool include_self, | 34 | void nmi_trigger_cpumask_backtrace(const cpumask_t *mask, |
35 | bool exclude_self, | ||
34 | void (*raise)(cpumask_t *mask)) | 36 | void (*raise)(cpumask_t *mask)) |
35 | { | 37 | { |
36 | int i, this_cpu = get_cpu(); | 38 | int i, this_cpu = get_cpu(); |
@@ -44,13 +46,22 @@ void nmi_trigger_all_cpu_backtrace(bool include_self, | |||
44 | return; | 46 | return; |
45 | } | 47 | } |
46 | 48 | ||
47 | cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask); | 49 | cpumask_copy(to_cpumask(backtrace_mask), mask); |
48 | if (!include_self) | 50 | if (exclude_self) |
49 | cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask)); | 51 | cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask)); |
50 | 52 | ||
53 | /* | ||
54 | * Don't try to send an NMI to this cpu; it may work on some | ||
55 | * architectures, but on others it may not, and we'll get | ||
56 | * information at least as useful just by doing a dump_stack() here. | ||
57 | * Note that nmi_cpu_backtrace(NULL) will clear the cpu bit. | ||
58 | */ | ||
59 | if (cpumask_test_cpu(this_cpu, to_cpumask(backtrace_mask))) | ||
60 | nmi_cpu_backtrace(NULL); | ||
61 | |||
51 | if (!cpumask_empty(to_cpumask(backtrace_mask))) { | 62 | if (!cpumask_empty(to_cpumask(backtrace_mask))) { |
52 | pr_info("Sending NMI to %s CPUs:\n", | 63 | pr_info("Sending NMI from CPU %d to CPUs %*pbl:\n", |
53 | (include_self ? "all" : "other")); | 64 | this_cpu, nr_cpumask_bits, to_cpumask(backtrace_mask)); |
54 | raise(to_cpumask(backtrace_mask)); | 65 | raise(to_cpumask(backtrace_mask)); |
55 | } | 66 | } |
56 | 67 | ||
@@ -77,11 +88,16 @@ bool nmi_cpu_backtrace(struct pt_regs *regs) | |||
77 | int cpu = smp_processor_id(); | 88 | int cpu = smp_processor_id(); |
78 | 89 | ||
79 | if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { | 90 | if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { |
80 | pr_warn("NMI backtrace for cpu %d\n", cpu); | 91 | if (regs && cpu_in_idle(instruction_pointer(regs))) { |
81 | if (regs) | 92 | pr_warn("NMI backtrace for cpu %d skipped: idling at pc %#lx\n", |
82 | show_regs(regs); | 93 | cpu, instruction_pointer(regs)); |
83 | else | 94 | } else { |
84 | dump_stack(); | 95 | pr_warn("NMI backtrace for cpu %d\n", cpu); |
96 | if (regs) | ||
97 | show_regs(regs); | ||
98 | else | ||
99 | dump_stack(); | ||
100 | } | ||
85 | cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); | 101 | cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); |
86 | return true; | 102 | return true; |
87 | } | 103 | } |