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

Byungchul Park
2016-01-27T12:01:57Z

changes form v3 to v4
- reuse a existing code as much as possible for preventing an infinite
recursive cycle.

changes from v2 to v3
- avoid printk() only in case of lockup suspected, not real lockup in
which case it does not help at all.
- consider not only console_sem.lock but also logbuf_lock which is used
by printk().

changes from v1 to v2
- only change comment and commit message esp. replacing "deadlock" with
"infinite recursive cycle", since it is not an actual deadlock.

thanks,
byungchul

-----8<-----
>From 7b0c6e48625632fa1732b619083dc550b5d924c6 Mon Sep 17 00:00:00 2001
From: Byungchul Park <byungchul.park@lge.com>
Date: Wed, 27 Jan 2016 18:11:55 +0900
Subject: [PATCH v4] lib/spinlock_debug.c: prevent a recursive cycle in the
debug code

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@lge.com>
---
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