[PATCH] MIPS: Fix arch_trigger_cpumask_backtrace()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



SysRq-L and RCU stall detector call arch_trigger_cpumask_backtrace() to
trigger other CPU's backtrace, but its behavior is totally broken. The
root cause is arch_trigger_cpumask_backtrace() use call-function IPI in
irq context, which trigger deadlocks in smp_call_function_single() and
smp_call_function_many().

This patch fix arch_trigger_cpumask_backtrace() by:
1, Use a dedecated IPI (SMP_CPU_BACKTRACE) to trigger backtraces;
2, If myself is in target cpumask, do backtrace and clear myself;
3, Use a spinlock to avoid parallel backtrace output;
4, Handle SMP_CPU_BACKTRACE IPI for Loongson-3.

I have attempted to implement SMP_CPU_BACKTRACE for all MIPS CPUs, but I
failed because some of their IPIs are not extensible. :(

Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Huacai Chen <chenhc@xxxxxxxxxx>
---
 arch/mips/include/asm/smp.h           |  3 +++
 arch/mips/kernel/process.c            | 23 ++++++++++++++++++-----
 arch/mips/loongson64/loongson-3/smp.c |  6 ++++++
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h
index 88ebd83..b0521f4 100644
--- a/arch/mips/include/asm/smp.h
+++ b/arch/mips/include/asm/smp.h
@@ -43,6 +43,7 @@ extern int __cpu_logical_map[NR_CPUS];
 /* Octeon - Tell another core to flush its icache */
 #define SMP_ICACHE_FLUSH	0x4
 #define SMP_ASK_C0COUNT		0x8
+#define SMP_CPU_BACKTRACE	0x10
 
 /* Mask of CPUs which are currently definitely operating coherently */
 extern cpumask_t cpu_coherent_mask;
@@ -81,6 +82,8 @@ static inline void __cpu_die(unsigned int cpu)
 extern void play_dead(void);
 #endif
 
+void arch_dump_stack(void);
+
 /*
  * This function will set up the necessary IPIs for Linux to communicate
  * with the CPUs in mask.
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 57028d4..647e15d 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -655,26 +655,39 @@ unsigned long arch_align_stack(unsigned long sp)
 	return sp & ALMASK;
 }
 
-static void arch_dump_stack(void *info)
+void arch_dump_stack(void)
 {
 	struct pt_regs *regs;
+	static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
 
+	arch_spin_lock(&lock);
 	regs = get_irq_regs();
 
 	if (regs)
 		show_regs(regs);
 
 	dump_stack();
+	arch_spin_unlock(&lock);
 }
 
 void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
 {
 	long this_cpu = get_cpu();
+	struct cpumask backtrace_mask;
+	extern const struct plat_smp_ops *mp_ops;
+
+	cpumask_copy(&backtrace_mask, mask);
+	if (cpumask_test_cpu(this_cpu, mask)) {
+		if (!exclude_self) {
+			struct pt_regs *regs = get_irq_regs();
+			if (regs)
+				show_regs(regs);
+			dump_stack();
+		}
+		cpumask_clear_cpu(this_cpu, &backtrace_mask);
+	}
 
-	if (cpumask_test_cpu(this_cpu, mask) && !exclude_self)
-		dump_stack();
-
-	smp_call_function_many(mask, arch_dump_stack, NULL, 1);
+	mp_ops->send_ipi_mask(&backtrace_mask, SMP_CPU_BACKTRACE);
 
 	put_cpu();
 }
diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c
index 8501109..0655114 100644
--- a/arch/mips/loongson64/loongson-3/smp.c
+++ b/arch/mips/loongson64/loongson-3/smp.c
@@ -291,6 +291,12 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
 		__wbflush(); /* Let others see the result ASAP */
 	}
 
+	if (action & SMP_CPU_BACKTRACE) {
+		irq_enter();
+		arch_dump_stack();
+		irq_exit();
+	}
+
 	if (irqs) {
 		int irq;
 		while ((irq = ffs(irqs))) {
-- 
2.7.0




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux