Skip to content

Commit 4a07791

Browse files
johnstultz-workPeter Zijlstra
authored andcommitted
locking/rtmutex: Make sure we wake anything on the wake_q when we release the lock->wait_lock
Bert reported seeing occasional boot hangs when running with PREEPT_RT and bisected it down to commit 894d1b3 ("locking/mutex: Remove wakeups from under mutex::wait_lock"). It looks like I missed a few spots where we drop the wait_lock and potentially call into schedule without waking up the tasks on the wake_q structure. Since the tasks being woken are ww_mutex tasks they need to be able to run to release the mutex and unblock the task that currently is planning to wake them. Thus we can deadlock. So make sure we wake the wake_q tasks when we unlock the wait_lock. Closes: https://lore.kernel.org/lkml/[email protected] Fixes: 894d1b3 ("locking/mutex: Remove wakeups from under mutex::wait_lock") Reported-by: Bert Karwatzki <[email protected]> Signed-off-by: John Stultz <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 78d4f34 commit 4a07791

File tree

2 files changed

+17
-3
lines changed

2 files changed

+17
-3
lines changed

kernel/locking/rtmutex.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,7 +1292,13 @@ static int __sched task_blocks_on_rt_mutex(struct rt_mutex_base *lock,
12921292
*/
12931293
get_task_struct(owner);
12941294

1295+
preempt_disable();
12951296
raw_spin_unlock_irq(&lock->wait_lock);
1297+
/* wake up any tasks on the wake_q before calling rt_mutex_adjust_prio_chain */
1298+
wake_up_q(wake_q);
1299+
wake_q_init(wake_q);
1300+
preempt_enable();
1301+
12961302

12971303
res = rt_mutex_adjust_prio_chain(owner, chwalk, lock,
12981304
next_lock, waiter, task);
@@ -1596,14 +1602,16 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,
15961602
* or TASK_UNINTERRUPTIBLE)
15971603
* @timeout: the pre-initialized and started timer, or NULL for none
15981604
* @waiter: the pre-initialized rt_mutex_waiter
1605+
* @wake_q: wake_q of tasks to wake when we drop the lock->wait_lock
15991606
*
16001607
* Must be called with lock->wait_lock held and interrupts disabled
16011608
*/
16021609
static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
16031610
struct ww_acquire_ctx *ww_ctx,
16041611
unsigned int state,
16051612
struct hrtimer_sleeper *timeout,
1606-
struct rt_mutex_waiter *waiter)
1613+
struct rt_mutex_waiter *waiter,
1614+
struct wake_q_head *wake_q)
16071615
__releases(&lock->wait_lock) __acquires(&lock->wait_lock)
16081616
{
16091617
struct rt_mutex *rtm = container_of(lock, struct rt_mutex, rtmutex);
@@ -1634,7 +1642,13 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
16341642
owner = rt_mutex_owner(lock);
16351643
else
16361644
owner = NULL;
1645+
preempt_disable();
16371646
raw_spin_unlock_irq(&lock->wait_lock);
1647+
if (wake_q) {
1648+
wake_up_q(wake_q);
1649+
wake_q_init(wake_q);
1650+
}
1651+
preempt_enable();
16381652

16391653
if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner))
16401654
rt_mutex_schedule();
@@ -1708,7 +1722,7 @@ static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock,
17081722

17091723
ret = task_blocks_on_rt_mutex(lock, waiter, current, ww_ctx, chwalk, wake_q);
17101724
if (likely(!ret))
1711-
ret = rt_mutex_slowlock_block(lock, ww_ctx, state, NULL, waiter);
1725+
ret = rt_mutex_slowlock_block(lock, ww_ctx, state, NULL, waiter, wake_q);
17121726

17131727
if (likely(!ret)) {
17141728
/* acquired the lock */

kernel/locking/rtmutex_api.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ int __sched rt_mutex_wait_proxy_lock(struct rt_mutex_base *lock,
383383
raw_spin_lock_irq(&lock->wait_lock);
384384
/* sleep on the mutex */
385385
set_current_state(TASK_INTERRUPTIBLE);
386-
ret = rt_mutex_slowlock_block(lock, NULL, TASK_INTERRUPTIBLE, to, waiter);
386+
ret = rt_mutex_slowlock_block(lock, NULL, TASK_INTERRUPTIBLE, to, waiter, NULL);
387387
/*
388388
* try_to_take_rt_mutex() sets the waiter bit unconditionally. We might
389389
* have to fix that up.

0 commit comments

Comments
 (0)