Skip to content

Commit 3d5c934

Browse files
committed
rtmutex: Handle deadlock detection smarter
Even in the case when deadlock detection is not requested by the caller, we can detect deadlocks. Right now the code stops the lock chain walk and keeps the waiter enqueued, even on itself. Silly not to yell when such a scenario is detected and to keep the waiter enqueued. Return -EDEADLK unconditionally and handle it at the call sites. The futex calls return -EDEADLK. The non futex ones dequeue the waiter, throw a warning and put the task into a schedule loop. Tagged for stable as it makes the code more robust. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Brad Mouring <bmouring@ni.com> Link: http://lkml.kernel.org/r/20140605152801.836501969@linutronix.de Cc: stable@vger.kernel.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
1 parent 951e273 commit 3d5c934

File tree

3 files changed

+38
-5
lines changed

3 files changed

+38
-5
lines changed

kernel/locking/rtmutex-debug.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,8 @@ static inline int debug_rt_mutex_detect_deadlock(struct rt_mutex_waiter *waiter,
3131
{
3232
return (waiter != NULL);
3333
}
34+
35+
static inline void rt_mutex_print_deadlock(struct rt_mutex_waiter *w)
36+
{
37+
debug_rt_mutex_print_deadlock(w);
38+
}

kernel/locking/rtmutex.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
314314
}
315315
put_task_struct(task);
316316

317-
return deadlock_detect ? -EDEADLK : 0;
317+
return -EDEADLK;
318318
}
319319
retry:
320320
/*
@@ -377,7 +377,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
377377
if (lock == orig_lock || rt_mutex_owner(lock) == top_task) {
378378
debug_rt_mutex_deadlock(deadlock_detect, orig_waiter, lock);
379379
raw_spin_unlock(&lock->wait_lock);
380-
ret = deadlock_detect ? -EDEADLK : 0;
380+
ret = -EDEADLK;
381381
goto out_unlock_pi;
382382
}
383383

@@ -548,7 +548,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
548548
* which is wrong, as the other waiter is not in a deadlock
549549
* situation.
550550
*/
551-
if (detect_deadlock && owner == task)
551+
if (owner == task)
552552
return -EDEADLK;
553553

554554
raw_spin_lock_irqsave(&task->pi_lock, flags);
@@ -763,6 +763,26 @@ __rt_mutex_slowlock(struct rt_mutex *lock, int state,
763763
return ret;
764764
}
765765

766+
static void rt_mutex_handle_deadlock(int res, int detect_deadlock,
767+
struct rt_mutex_waiter *w)
768+
{
769+
/*
770+
* If the result is not -EDEADLOCK or the caller requested
771+
* deadlock detection, nothing to do here.
772+
*/
773+
if (res != -EDEADLOCK || detect_deadlock)
774+
return;
775+
776+
/*
777+
* Yell lowdly and stop the task right here.
778+
*/
779+
rt_mutex_print_deadlock(w);
780+
while (1) {
781+
set_current_state(TASK_INTERRUPTIBLE);
782+
schedule();
783+
}
784+
}
785+
766786
/*
767787
* Slow path lock function:
768788
*/
@@ -802,8 +822,10 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
802822

803823
set_current_state(TASK_RUNNING);
804824

805-
if (unlikely(ret))
825+
if (unlikely(ret)) {
806826
remove_waiter(lock, &waiter);
827+
rt_mutex_handle_deadlock(ret, detect_deadlock, &waiter);
828+
}
807829

808830
/*
809831
* try_to_take_rt_mutex() sets the waiter bit
@@ -1112,7 +1134,8 @@ int rt_mutex_start_proxy_lock(struct rt_mutex *lock,
11121134
return 1;
11131135
}
11141136

1115-
ret = task_blocks_on_rt_mutex(lock, waiter, task, detect_deadlock);
1137+
/* We enforce deadlock detection for futexes */
1138+
ret = task_blocks_on_rt_mutex(lock, waiter, task, 1);
11161139

11171140
if (ret && !rt_mutex_owner(lock)) {
11181141
/*

kernel/locking/rtmutex.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,8 @@
2424
#define debug_rt_mutex_print_deadlock(w) do { } while (0)
2525
#define debug_rt_mutex_detect_deadlock(w,d) (d)
2626
#define debug_rt_mutex_reset_waiter(w) do { } while (0)
27+
28+
static inline void rt_mutex_print_deadlock(struct rt_mutex_waiter *w)
29+
{
30+
WARN(1, "rtmutex deadlock detected\n");
31+
}

0 commit comments

Comments
 (0)