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 @@  #include <linux/delay.h>  #include <linux/kprobes.h>  #include <linux/nmi.h> +#include <linux/cpu.h> -#ifdef arch_trigger_all_cpu_backtrace +#ifdef arch_trigger_cpumask_backtrace  /* For reliability, we're prepared to waste bits here. */  static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; -/* "in progress" flag of arch_trigger_all_cpu_backtrace */ +/* "in progress" flag of arch_trigger_cpumask_backtrace */  static unsigned long backtrace_flag;  /* - * When raise() is called it will be is passed a pointer to the + * When raise() is called it will be passed a pointer to the   * backtrace_mask. Architectures that call nmi_cpu_backtrace()   * directly from their raise() functions may rely on the mask   * they are passed being updated as a side effect of this call.   */ -void nmi_trigger_all_cpu_backtrace(bool include_self, +void nmi_trigger_cpumask_backtrace(const cpumask_t *mask, +				   bool exclude_self,  				   void (*raise)(cpumask_t *mask))  {  	int i, this_cpu = get_cpu(); @@ -44,13 +46,22 @@ void nmi_trigger_all_cpu_backtrace(bool include_self,  		return;  	} -	cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask); -	if (!include_self) +	cpumask_copy(to_cpumask(backtrace_mask), mask); +	if (exclude_self)  		cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask)); +	/* +	 * Don't try to send an NMI to this cpu; it may work on some +	 * architectures, but on others it may not, and we'll get +	 * information at least as useful just by doing a dump_stack() here. +	 * Note that nmi_cpu_backtrace(NULL) will clear the cpu bit. +	 */ +	if (cpumask_test_cpu(this_cpu, to_cpumask(backtrace_mask))) +		nmi_cpu_backtrace(NULL); +  	if (!cpumask_empty(to_cpumask(backtrace_mask))) { -		pr_info("Sending NMI to %s CPUs:\n", -			(include_self ? "all" : "other")); +		pr_info("Sending NMI from CPU %d to CPUs %*pbl:\n", +			this_cpu, nr_cpumask_bits, to_cpumask(backtrace_mask));  		raise(to_cpumask(backtrace_mask));  	} @@ -77,11 +88,16 @@ bool nmi_cpu_backtrace(struct pt_regs *regs)  	int cpu = smp_processor_id();  	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { -		pr_warn("NMI backtrace for cpu %d\n", cpu); -		if (regs) -			show_regs(regs); -		else -			dump_stack(); +		if (regs && cpu_in_idle(instruction_pointer(regs))) { +			pr_warn("NMI backtrace for cpu %d skipped: idling at pc %#lx\n", +				cpu, instruction_pointer(regs)); +		} else { +			pr_warn("NMI backtrace for cpu %d\n", cpu); +			if (regs) +				show_regs(regs); +			else +				dump_stack(); +		}  		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));  		return true;  	}  |