aboutsummaryrefslogtreecommitdiffstats
path: root/lib/nmi_backtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nmi_backtrace.c')
-rw-r--r--lib/nmi_backtrace.c42
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. */
22static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; 23static 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 */
25static unsigned long backtrace_flag; 26static 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 */
33void nmi_trigger_all_cpu_backtrace(bool include_self, 34void 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 }