|
@@ -29,6 +29,7 @@
|
|
|
#include <linux/kallsyms.h>
|
|
|
#include <linux/random.h>
|
|
|
#include <linux/prctl.h>
|
|
|
+#include <linux/nmi.h>
|
|
|
|
|
|
#include <asm/asm.h>
|
|
|
#include <asm/bootinfo.h>
|
|
@@ -655,28 +656,42 @@ unsigned long arch_align_stack(unsigned long sp)
|
|
|
return sp & ALMASK;
|
|
|
}
|
|
|
|
|
|
-static void arch_dump_stack(void *info)
|
|
|
-{
|
|
|
- struct pt_regs *regs;
|
|
|
+static DEFINE_PER_CPU(call_single_data_t, backtrace_csd);
|
|
|
+static struct cpumask backtrace_csd_busy;
|
|
|
|
|
|
- regs = get_irq_regs();
|
|
|
-
|
|
|
- if (regs)
|
|
|
- show_regs(regs);
|
|
|
- else
|
|
|
- dump_stack();
|
|
|
+static void handle_backtrace(void *info)
|
|
|
+{
|
|
|
+ nmi_cpu_backtrace(get_irq_regs());
|
|
|
+ cpumask_clear_cpu(smp_processor_id(), &backtrace_csd_busy);
|
|
|
}
|
|
|
|
|
|
-void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
|
|
|
+static void raise_backtrace(cpumask_t *mask)
|
|
|
{
|
|
|
- long this_cpu = get_cpu();
|
|
|
+ call_single_data_t *csd;
|
|
|
+ int cpu;
|
|
|
|
|
|
- if (cpumask_test_cpu(this_cpu, mask) && !exclude_self)
|
|
|
- dump_stack();
|
|
|
+ for_each_cpu(cpu, mask) {
|
|
|
+ /*
|
|
|
+ * If we previously sent an IPI to the target CPU & it hasn't
|
|
|
+ * cleared its bit in the busy cpumask then it didn't handle
|
|
|
+ * our previous IPI & it's not safe for us to reuse the
|
|
|
+ * call_single_data_t.
|
|
|
+ */
|
|
|
+ if (cpumask_test_and_set_cpu(cpu, &backtrace_csd_busy)) {
|
|
|
+ pr_warn("Unable to send backtrace IPI to CPU%u - perhaps it hung?\n",
|
|
|
+ cpu);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- smp_call_function_many(mask, arch_dump_stack, NULL, 1);
|
|
|
+ csd = &per_cpu(backtrace_csd, cpu);
|
|
|
+ csd->func = handle_backtrace;
|
|
|
+ smp_call_function_single_async(cpu, csd);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- put_cpu();
|
|
|
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
|
|
|
+{
|
|
|
+ nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_backtrace);
|
|
|
}
|
|
|
|
|
|
int mips_get_process_fp_mode(struct task_struct *task)
|