2015-05-14 16:44:11

by Rabin Vincent

[permalink] [raw]
Subject: [PATCH 1/5] CRISv32: add support for irqflags tracing

Add support irqflags tracing, which is required for things like lockdep
and ftrace.

Signed-off-by: Rabin Vincent <[email protected]>
---
arch/cris/Kconfig | 4 ++++
arch/cris/arch-v32/kernel/entry.S | 11 +++++++++++
arch/cris/kernel/irq.c | 6 +++++-
3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 0314e32..efe829e 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -36,6 +36,10 @@ config FORCE_MAX_ZONEORDER
int
default 6

+config TRACE_IRQFLAGS_SUPPORT
+ depends on ETRAX_ARCH_V32
+ def_bool y
+
config CRIS
bool
default y
diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S
index 026a0b2..3591c37 100644
--- a/arch/cris/arch-v32/kernel/entry.S
+++ b/arch/cris/arch-v32/kernel/entry.S
@@ -240,6 +240,17 @@ ret_from_sys_call:

.type _Rexit,@function
_Rexit:
+#if defined(CONFIG_TRACE_IRQFLAGS)
+ addoq +PT_ccs, $sp, $acr
+ move.d [$acr], $r0
+ btstq 15, $r0 ; I1
+ bpl 1f
+ nop
+ jsr trace_hardirqs_on
+ nop
+1:
+#endif
+
;; This epilogue MUST match the prologues in multiple_interrupt, irq.h
;; and ptregs.h.
addq 4, $sp ; Skip orig_r10.
diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c
index dd0be5d..694850e 100644
--- a/arch/cris/kernel/irq.c
+++ b/arch/cris/kernel/irq.c
@@ -45,7 +45,11 @@
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
{
unsigned long sp;
- struct pt_regs *old_regs = set_irq_regs(regs);
+ struct pt_regs *old_regs;
+
+ trace_hardirqs_off();
+
+ old_regs = set_irq_regs(regs);
irq_enter();
sp = rdsp();
if (unlikely((sp & (PAGE_SIZE - 1)) < (PAGE_SIZE/8))) {
--
2.1.4


2015-05-14 16:44:14

by Rabin Vincent

[permalink] [raw]
Subject: [PATCH 2/5] CRISv32: annotate irq enable in idle loop

Use a call to local_irq_enable() instead of incline asm so that the
irqsoff latency tracer knows that interrupts are enabled here.

Signed-off-by: Rabin Vincent <[email protected]>
---
arch/cris/arch-v32/kernel/process.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c
index cebd32e..c7ce784 100644
--- a/arch/cris/arch-v32/kernel/process.c
+++ b/arch/cris/arch-v32/kernel/process.c
@@ -23,9 +23,9 @@ extern void stop_watchdog(void);
/* We use this if we don't have any better idle routine. */
void default_idle(void)
{
+ local_irq_enable();
/* Halt until exception. */
- __asm__ volatile("ei \n\t"
- "halt ");
+ __asm__ volatile("halt");
}

/*
--
2.1.4

2015-05-14 16:45:57

by Rabin Vincent

[permalink] [raw]
Subject: [PATCH 3/5] CRIS: add STACKTRACE_SUPPORT

Add stacktrace support, which is required for lockdep and tracing. The
stack tracing simply looks at all kernel text symbols found on the
stack, similar to the trap stack dumping code, which can also be
converted to use this.

Signed-off-by: Rabin Vincent <[email protected]>
---
arch/cris/Kconfig | 3 ++
arch/cris/include/asm/stacktrace.h | 8 ++++
arch/cris/kernel/Makefile | 1 +
arch/cris/kernel/stacktrace.c | 76 ++++++++++++++++++++++++++++++++++++++
4 files changed, 88 insertions(+)
create mode 100644 arch/cris/include/asm/stacktrace.h
create mode 100644 arch/cris/kernel/stacktrace.c

diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index efe829e..bb6a4f9 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -40,6 +40,9 @@ config TRACE_IRQFLAGS_SUPPORT
depends on ETRAX_ARCH_V32
def_bool y

+config STACKTRACE_SUPPORT
+ def_bool y
+
config CRIS
bool
default y
diff --git a/arch/cris/include/asm/stacktrace.h b/arch/cris/include/asm/stacktrace.h
new file mode 100644
index 0000000..2d90856
--- /dev/null
+++ b/arch/cris/include/asm/stacktrace.h
@@ -0,0 +1,8 @@
+#ifndef __CRIS_STACKTRACE_H
+#define __CRIS_STACKTRACE_H
+
+void walk_stackframe(unsigned long sp,
+ int (*fn)(unsigned long addr, void *data),
+ void *data);
+
+#endif
diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile
index edef71f..5fae398 100644
--- a/arch/cris/kernel/Makefile
+++ b/arch/cris/kernel/Makefile
@@ -8,6 +8,7 @@ extra-y := vmlinux.lds

obj-y := process.o traps.o irq.o ptrace.o setup.o time.o sys_cris.o
obj-y += devicetree.o
+obj-y += stacktrace.o

obj-$(CONFIG_MODULES) += crisksyms.o
obj-$(CONFIG_MODULES) += module.o
diff --git a/arch/cris/kernel/stacktrace.c b/arch/cris/kernel/stacktrace.c
new file mode 100644
index 0000000..99838c7
--- /dev/null
+++ b/arch/cris/kernel/stacktrace.c
@@ -0,0 +1,76 @@
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/stacktrace.h>
+#include <asm/stacktrace.h>
+
+void walk_stackframe(unsigned long sp,
+ int (*fn)(unsigned long addr, void *data),
+ void *data)
+{
+ unsigned long high = ALIGN(sp, THREAD_SIZE);
+
+ for (; sp <= high - 4; sp += 4) {
+ unsigned long addr = *(unsigned long *) sp;
+
+ if (!kernel_text_address(addr))
+ continue;
+
+ if (fn(addr, data))
+ break;
+ }
+}
+
+struct stack_trace_data {
+ struct stack_trace *trace;
+ unsigned int no_sched_functions;
+ unsigned int skip;
+};
+
+#ifdef CONFIG_STACKTRACE
+
+static int save_trace(unsigned long addr, void *d)
+{
+ struct stack_trace_data *data = d;
+ struct stack_trace *trace = data->trace;
+
+ if (data->no_sched_functions && in_sched_functions(addr))
+ return 0;
+
+ if (data->skip) {
+ data->skip--;
+ return 0;
+ }
+
+ trace->entries[trace->nr_entries++] = addr;
+
+ return trace->nr_entries >= trace->max_entries;
+}
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+ struct stack_trace_data data;
+ unsigned long sp;
+
+ data.trace = trace;
+ data.skip = trace->skip;
+
+ if (tsk != current) {
+ data.no_sched_functions = 1;
+ sp = tsk->thread.ksp;
+ } else {
+ data.no_sched_functions = 0;
+ sp = rdsp();
+ }
+
+ walk_stackframe(sp, save_trace, &data);
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+
+void save_stack_trace(struct stack_trace *trace)
+{
+ save_stack_trace_tsk(current, trace);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
+
+#endif /* CONFIG_STACKTRACE */
--
2.1.4

2015-05-14 16:45:53

by Rabin Vincent

[permalink] [raw]
Subject: [PATCH 4/5] CRISv32: enable LOCKDEP_SUPPORT

Now that we have stack tracing and irq flags tracing support,
we can also enable lockdep support

Signed-off-by: Rabin Vincent <[email protected]>
---
arch/cris/Kconfig | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index bb6a4f9..41d37d2 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -43,6 +43,10 @@ config TRACE_IRQFLAGS_SUPPORT
config STACKTRACE_SUPPORT
def_bool y

+config LOCKDEP_SUPPORT
+ depends on ETRAX_ARCH_V32
+ def_bool y
+
config CRIS
bool
default y
--
2.1.4

2015-05-14 16:45:49

by Rabin Vincent

[permalink] [raw]
Subject: [PATCH 5/5] CRIS: fix switch_mm() lockdep splat

With lockdep support implemented on CRISv32, we get the following splat.
switch_mm() can be called both from the scheduler() (with interrupts
disabled) and from flush_old_exec (via activate_mm()), with interrupts
enabled. Fix it by disabling interrupts in activate_mm(), similar to
powerpc and hexagon.

t======================================================
[ INFO: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected ]
3.19.0-08802-g20bc9f1-dirty #323 Not tainted
------------------------------------------------------
init/1 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire:
(mmu_context_lock){+.+...}, at: [<c0009290>] switch_mm+0x22/0xc6

and this task is already holding:
(&rq->lock){-.-.-.}, at: [<c01a0756>] __schedule+0x5e/0x648
which would create a new lock dependency:
(&rq->lock){-.-.-.} -> (mmu_context_lock){+.+...}

but this new dependency connects a HARDIRQ-irq-safe lock:
(&rq->lock){-.-.-.}
... which became HARDIRQ-irq-safe at:
[<c002b03c>] scheduler_tick+0x28/0x5e
[<c0007c6c>] timer_interrupt+0x4e/0x6a
[<c0043ac4>] handle_irq_event_percpu+0x54/0x13c
[<c004343c>] generic_handle_irq+0x2a/0x36

to a HARDIRQ-irq-unsafe lock:
(mmu_context_lock){+.+...}
... which became HARDIRQ-irq-unsafe at:
... [<c0039e60>] __lock_acquire+0x8f8/0x1d9c
[<c0009290>] switch_mm+0x22/0xc6
[<c009c260>] flush_old_exec+0x500/0x5d4
[<c00da4c6>] load_elf_phdrs+0x7a/0x84
[<c00dbdb0>] load_elf_binary+0x21c/0x13b4
[<c009cdb6>] do_execve+0x22/0x2c
[<c001dcf2>] ____call_usermodehelper+0x0/0x154
[<c000581e>] ret_from_kernel_thread+0xe/0x14

other info that might help us debug this:

Possible interrupt unsafe locking scenario:

CPU0 CPU1
---- ----
lock(mmu_context_lock);
local_irq_disable();
lock(&rq->lock);
lock(mmu_context_lock);
<Interrupt>
lock(&rq->lock);

*** DEADLOCK ***

1 lock held by init/1:
#0: (&rq->lock){-.-.-.}, at: [<c01a0756>] __schedule+0x5e/0x648

Call Trace:
[<c019fe9e>] printk+0x0/0x4e
[<c00368f8>] print_shortest_lock_dependencies+0x0/0x15c
[<c0048628>] print_stack_trace+0x0/0x88
[<c0038912>] __lock_is_held+0x3e/0x5e
[<c003b894>] lock_acquire+0x8a/0xcc
[<c01a50c4>] _raw_spin_lock+0x44/0x7a
[<c0009290>] switch_mm+0x22/0xc6
[<c01a06f8>] __schedule+0x0/0x648
[<c01a0d76>] schedule+0x36/0x7c
[<c0037d04>] trace_hardirqs_on+0x0/0x1e
[<c0004e18>] do_work_pending+0x30/0xd4
[<c000591a>] _work_pending+0xe/0x12

Signed-off-by: Rabin Vincent <[email protected]>
---
arch/cris/include/asm/mmu_context.h | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/cris/include/asm/mmu_context.h b/arch/cris/include/asm/mmu_context.h
index 1d45fd6..349acfd 100644
--- a/arch/cris/include/asm/mmu_context.h
+++ b/arch/cris/include/asm/mmu_context.h
@@ -11,7 +11,14 @@ extern void switch_mm(struct mm_struct *prev, struct mm_struct *next,

#define deactivate_mm(tsk,mm) do { } while (0)

-#define activate_mm(prev,next) switch_mm((prev),(next),NULL)
+static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ switch_mm(prev, next, NULL);
+ local_irq_restore(flags);
+}

/* current active pgd - this is similar to other processors pgd
* registers like cr3 on the i386
--
2.1.4