[PATCH v4] lib/spinlock_debug.c: prevent a recursive cycle in the debug code

From: Byungchul Park
Date: Wed Jan 27 2016 - 04:11:55 EST


It causes an infinite recursive cycle when using CONFIG_DEBUG_SPINLOCK,
in the spin_dump(). Backtrace prints printk() -> console_trylock() ->
do_raw_spin_lock() -> spin_dump() -> printk()... infinitely.

When the debug spinlock code is called from printk(), we should prevent
calling spin_dump() and the like, calling printk() again in that context.

Signed-off-by: Byungchul Park <byungchul.park@xxxxxxx>
---
include/linux/debug_locks.h | 4 ++++
kernel/locking/spinlock_debug.c | 14 +++++++++++---
2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h
index 822c135..b0f977e 100644
--- a/include/linux/debug_locks.h
+++ b/include/linux/debug_locks.h
@@ -10,6 +10,10 @@ struct task_struct;
extern int debug_locks;
extern int debug_locks_silent;

+static inline void __debug_locks_on(void)
+{
+ debug_locks = 1;
+}

static inline int __debug_locks_off(void)
{
diff --git a/kernel/locking/spinlock_debug.c b/kernel/locking/spinlock_debug.c
index 0374a59..65177ba 100644
--- a/kernel/locking/spinlock_debug.c
+++ b/kernel/locking/spinlock_debug.c
@@ -113,11 +113,19 @@ static void __spin_lock_debug(raw_spinlock_t *lock)
return;
__delay(1);
}
- /* lockup suspected: */
- spin_dump(lock, "lockup suspected");
+
+ /*
+ * We should prevent calling printk() further, since it would cause
+ * an infinite recursive cycle if it's called from printk()!
+ */
+ if (__debug_locks_off()) {
+ /* lockup suspected: */
+ spin_dump(lock, "lockup suspected");
#ifdef CONFIG_SMP
- trigger_all_cpu_backtrace();
+ trigger_all_cpu_backtrace();
#endif
+ __debug_locks_on();
+ }

/*
* The trylock above was causing a livelock. Give the lower level arch
--
1.9.1