Skip to content

Commit

Permalink
ARM: 8439/1: Fix backtrace generation when IPI is masked
Browse files Browse the repository at this point in the history
Currently on ARM when <SysRq-L> is triggered from an interrupt handler
(e.g. a SysRq issued using UART or kbd) the main CPU will wedge for ten
seconds with interrupts masked before issuing a backtrace for every CPU
except itself.

The new backtrace code introduced by commit 96f0e00 ("ARM: add
basic support for on-demand backtrace of other CPUs") does not work
correctly when run from an interrupt handler because IPI_CPU_BACKTRACE
is used to generate the backtrace on all CPUs but cannot preempt the
current calling context.

This can be fixed by detecting that the calling context cannot be
preempted and issuing the backtrace directly in this case. Issuing
directly leaves us without any pt_regs to pass to nmi_cpu_backtrace()
so we also modify the generic code to call dump_stack() when its
argument is NULL.

Acked-by: Hillf Danton <hillf.zj@alibaba-inc.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Daniel Thompson authored and Russell King committed Oct 3, 2015
1 parent 001bf45 commit 0768330
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 1 deletion.
9 changes: 9 additions & 0 deletions arch/arm/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,15 @@ core_initcall(register_cpufreq_notifier);

static void raise_nmi(cpumask_t *mask)
{
/*
* Generate the backtrace directly if we are running in a calling
* context that is not preemptible by the backtrace IPI. Note
* that nmi_cpu_backtrace() automatically removes the current cpu
* from mask.
*/
if (cpumask_test_cpu(smp_processor_id(), mask) && irqs_disabled())
nmi_cpu_backtrace(NULL);

smp_cross_call(mask, IPI_CPU_BACKTRACE);
}

Expand Down
11 changes: 10 additions & 1 deletion lib/nmi_backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ static void print_seq_line(struct nmi_seq_buf *s, int start, int end)
printk("%.*s", (end - start) + 1, buf);
}

/*
* When raise() is called it will be is 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 (*raise)(cpumask_t *mask))
{
Expand Down Expand Up @@ -149,7 +155,10 @@ bool nmi_cpu_backtrace(struct pt_regs *regs)
/* Replace printk to write into the NMI seq */
this_cpu_write(printk_func, nmi_vprintk);
pr_warn("NMI backtrace for cpu %d\n", cpu);
show_regs(regs);
if (regs)
show_regs(regs);
else
dump_stack();
this_cpu_write(printk_func, printk_func_save);

cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
Expand Down

0 comments on commit 0768330

Please sign in to comment.