From 94d24fc47219219b5aa23b45956cc37ee5aa5b01 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 7 Jun 2011 11:17:30 +0200 Subject: [PATCH 1/3] printk, lockdep: Disable lock debugging on zap_locks() zap_locks() is used by printk() in a last ditch effort to get data out, clearly we cannot trust lock state after this so make it disable lock debugging. Also don't treat printk recursion through lockdep as a normal recursion bug but try hard to get the lockdep splat out. Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-kqxwmo4xz37e1s8w0xopvr0q@git.kernel.org Signed-off-by: Ingo Molnar --- include/linux/lockdep.h | 4 ++++ kernel/printk.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index b6a56e37284c..d36619ead3ba 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -343,6 +343,8 @@ extern void lockdep_trace_alloc(gfp_t mask); #define lockdep_assert_held(l) WARN_ON(debug_locks && !lockdep_is_held(l)) +#define lockdep_recursing(tsk) ((tsk)->lockdep_recursion) + #else /* !LOCKDEP */ static inline void lockdep_off(void) @@ -392,6 +394,8 @@ struct lock_class_key { }; #define lockdep_assert_held(l) do { } while (0) +#define lockdep_recursing(tsk) (0) + #endif /* !LOCKDEP */ #ifdef CONFIG_LOCK_STAT diff --git a/kernel/printk.c b/kernel/printk.c index 1455a0d4eedd..6d087944e72a 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -688,6 +688,7 @@ static void zap_locks(void) oops_timestamp = jiffies; + debug_locks_off(); /* If a crash is occurring, make sure we can't deadlock */ raw_spin_lock_init(&logbuf_lock); /* And make sure that we print immediately */ @@ -856,7 +857,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) * recursion and return - but flag the recursion so that * it can be printed at the next appropriate moment: */ - if (!oops_in_progress) { + if (!oops_in_progress && !lockdep_recursing(current)) { recursion_bug = 1; goto out_restore_irqs; } From 47ff5c95db598184122aa634fa3452c0eecea877 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 7 Jun 2011 11:17:30 +0200 Subject: [PATCH 2/3] printk, lockdep: Remove superfluous preempt_disable() The raw_lock_irq_{save,restore}() already implies a non-preemptibility. Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar --- kernel/printk.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/printk.c b/kernel/printk.c index 6d087944e72a..ba5ee0435821 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -841,7 +841,6 @@ asmlinkage int vprintk(const char *fmt, va_list args) boot_delay_msec(); printk_delay(); - preempt_disable(); /* This stops the holder of console_sem just where we want him */ raw_local_irq_save(flags); this_cpu = smp_processor_id(); @@ -965,7 +964,6 @@ asmlinkage int vprintk(const char *fmt, va_list args) out_restore_irqs: raw_local_irq_restore(flags); - preempt_enable(); return printed_len; } EXPORT_SYMBOL(printk); From 1a9a8aefa8f0530c97f4606ab7a2fc01fe31e9c1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 7 Jun 2011 11:17:30 +0200 Subject: [PATCH 3/3] printk, lockdep: Switch to tracked irq ops Switch to local_irq_ ops so that the irq state is properly tracked (raw_local_irq_* isn't tracked by lockdep, causing confusion). Possible now that commit dd4e5d3ac4a ("lockdep: Fix trace_[soft,hard]irqs_[on,off]() recursion") cured the reason we needed the raw_ ops. Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar --- kernel/printk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/printk.c b/kernel/printk.c index ba5ee0435821..dfd8f73dcb76 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -842,7 +842,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) printk_delay(); /* This stops the holder of console_sem just where we want him */ - raw_local_irq_save(flags); + local_irq_save(flags); this_cpu = smp_processor_id(); /* @@ -962,7 +962,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) lockdep_on(); out_restore_irqs: - raw_local_irq_restore(flags); + local_irq_restore(flags); return printed_len; }