Skip to content

Commit d14f9e9

Browse files
Sebastian Andrzej SiewiorPeter Zijlstra
Sebastian Andrzej Siewior
authored and
Peter Zijlstra
committed
locking/rtmutex: Use rt_mutex specific scheduler helpers
Have rt_mutex use the rt_mutex specific scheduler helpers to avoid recursion vs rtlock on the PI state. [[ peterz: adapted to new names ]] Reported-by: Crystal Wood <[email protected]> Signed-off-by: Sebastian Andrzej Siewior <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 6b596e6 commit d14f9e9

File tree

5 files changed

+40
-3
lines changed

5 files changed

+40
-3
lines changed

kernel/futex/pi.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0-or-later
22

33
#include <linux/slab.h>
4+
#include <linux/sched/rt.h>
45
#include <linux/sched/task.h>
56

67
#include "futex.h"
@@ -1002,6 +1003,12 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
10021003
goto no_block;
10031004
}
10041005

1006+
/*
1007+
* Must be done before we enqueue the waiter, here is unfortunately
1008+
* under the hb lock, but that *should* work because it does nothing.
1009+
*/
1010+
rt_mutex_pre_schedule();
1011+
10051012
rt_mutex_init_waiter(&rt_waiter);
10061013

10071014
/*
@@ -1052,6 +1059,10 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
10521059
if (ret && !rt_mutex_cleanup_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter))
10531060
ret = 0;
10541061

1062+
/*
1063+
* Waiter is unqueued.
1064+
*/
1065+
rt_mutex_post_schedule();
10551066
no_block:
10561067
/*
10571068
* Fixup the pi_state owner and possibly acquire the lock if we

kernel/locking/rtmutex.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,7 +1632,7 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
16321632
raw_spin_unlock_irq(&lock->wait_lock);
16331633

16341634
if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner))
1635-
schedule();
1635+
rt_mutex_schedule();
16361636

16371637
raw_spin_lock_irq(&lock->wait_lock);
16381638
set_current_state(state);
@@ -1661,7 +1661,7 @@ static void __sched rt_mutex_handle_deadlock(int res, int detect_deadlock,
16611661
WARN(1, "rtmutex deadlock detected\n");
16621662
while (1) {
16631663
set_current_state(TASK_INTERRUPTIBLE);
1664-
schedule();
1664+
rt_mutex_schedule();
16651665
}
16661666
}
16671667

@@ -1756,6 +1756,15 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock,
17561756
unsigned long flags;
17571757
int ret;
17581758

1759+
/*
1760+
* Do all pre-schedule work here, before we queue a waiter and invoke
1761+
* PI -- any such work that trips on rtlock (PREEMPT_RT spinlock) would
1762+
* otherwise recurse back into task_blocks_on_rt_mutex() through
1763+
* rtlock_slowlock() and will then enqueue a second waiter for this
1764+
* same task and things get really confusing real fast.
1765+
*/
1766+
rt_mutex_pre_schedule();
1767+
17591768
/*
17601769
* Technically we could use raw_spin_[un]lock_irq() here, but this can
17611770
* be called in early boot if the cmpxchg() fast path is disabled
@@ -1767,6 +1776,7 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock,
17671776
raw_spin_lock_irqsave(&lock->wait_lock, flags);
17681777
ret = __rt_mutex_slowlock_locked(lock, ww_ctx, state);
17691778
raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
1779+
rt_mutex_post_schedule();
17701780

17711781
return ret;
17721782
}

kernel/locking/rwbase_rt.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,
7171
struct rt_mutex_base *rtm = &rwb->rtmutex;
7272
int ret;
7373

74+
rwbase_pre_schedule();
7475
raw_spin_lock_irq(&rtm->wait_lock);
7576

7677
/*
@@ -125,6 +126,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,
125126
rwbase_rtmutex_unlock(rtm);
126127

127128
trace_contention_end(rwb, ret);
129+
rwbase_post_schedule();
128130
return ret;
129131
}
130132

@@ -237,6 +239,8 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
237239
/* Force readers into slow path */
238240
atomic_sub(READER_BIAS, &rwb->readers);
239241

242+
rwbase_pre_schedule();
243+
240244
raw_spin_lock_irqsave(&rtm->wait_lock, flags);
241245
if (__rwbase_write_trylock(rwb))
242246
goto out_unlock;
@@ -248,6 +252,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
248252
if (rwbase_signal_pending_state(state, current)) {
249253
rwbase_restore_current_state();
250254
__rwbase_write_unlock(rwb, 0, flags);
255+
rwbase_post_schedule();
251256
trace_contention_end(rwb, -EINTR);
252257
return -EINTR;
253258
}
@@ -266,6 +271,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
266271

267272
out_unlock:
268273
raw_spin_unlock_irqrestore(&rtm->wait_lock, flags);
274+
rwbase_post_schedule();
269275
return 0;
270276
}
271277

kernel/locking/rwsem.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1427,8 +1427,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
14271427
#define rwbase_signal_pending_state(state, current) \
14281428
signal_pending_state(state, current)
14291429

1430+
#define rwbase_pre_schedule() \
1431+
rt_mutex_pre_schedule()
1432+
14301433
#define rwbase_schedule() \
1431-
schedule()
1434+
rt_mutex_schedule()
1435+
1436+
#define rwbase_post_schedule() \
1437+
rt_mutex_post_schedule()
14321438

14331439
#include "rwbase_rt.c"
14341440

kernel/locking/spinlock_rt.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,13 @@ static __always_inline int rwbase_rtmutex_trylock(struct rt_mutex_base *rtm)
184184

185185
#define rwbase_signal_pending_state(state, current) (0)
186186

187+
#define rwbase_pre_schedule()
188+
187189
#define rwbase_schedule() \
188190
schedule_rtlock()
189191

192+
#define rwbase_post_schedule()
193+
190194
#include "rwbase_rt.c"
191195
/*
192196
* The common functions which get wrapped into the rwlock API.

0 commit comments

Comments
 (0)