Commit d14f9e93 authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by Peter Zijlstra

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: default avatarCrystal Wood <swood@redhat.com>
Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20230908162254.999499-6-bigeasy@linutronix.de
parent 6b596e62
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched/rt.h>
#include <linux/sched/task.h> #include <linux/sched/task.h>
#include "futex.h" #include "futex.h"
...@@ -1002,6 +1003,12 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl ...@@ -1002,6 +1003,12 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
goto no_block; goto no_block;
} }
/*
* Must be done before we enqueue the waiter, here is unfortunately
* under the hb lock, but that *should* work because it does nothing.
*/
rt_mutex_pre_schedule();
rt_mutex_init_waiter(&rt_waiter); rt_mutex_init_waiter(&rt_waiter);
/* /*
...@@ -1052,6 +1059,10 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl ...@@ -1052,6 +1059,10 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
if (ret && !rt_mutex_cleanup_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter)) if (ret && !rt_mutex_cleanup_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter))
ret = 0; ret = 0;
/*
* Waiter is unqueued.
*/
rt_mutex_post_schedule();
no_block: no_block:
/* /*
* Fixup the pi_state owner and possibly acquire the lock if we * Fixup the pi_state owner and possibly acquire the lock if we
......
...@@ -1632,7 +1632,7 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock, ...@@ -1632,7 +1632,7 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
raw_spin_unlock_irq(&lock->wait_lock); raw_spin_unlock_irq(&lock->wait_lock);
if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner)) if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner))
schedule(); rt_mutex_schedule();
raw_spin_lock_irq(&lock->wait_lock); raw_spin_lock_irq(&lock->wait_lock);
set_current_state(state); set_current_state(state);
...@@ -1661,7 +1661,7 @@ static void __sched rt_mutex_handle_deadlock(int res, int detect_deadlock, ...@@ -1661,7 +1661,7 @@ static void __sched rt_mutex_handle_deadlock(int res, int detect_deadlock,
WARN(1, "rtmutex deadlock detected\n"); WARN(1, "rtmutex deadlock detected\n");
while (1) { while (1) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule(); rt_mutex_schedule();
} }
} }
...@@ -1756,6 +1756,15 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, ...@@ -1756,6 +1756,15 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock,
unsigned long flags; unsigned long flags;
int ret; int ret;
/*
* Do all pre-schedule work here, before we queue a waiter and invoke
* PI -- any such work that trips on rtlock (PREEMPT_RT spinlock) would
* otherwise recurse back into task_blocks_on_rt_mutex() through
* rtlock_slowlock() and will then enqueue a second waiter for this
* same task and things get really confusing real fast.
*/
rt_mutex_pre_schedule();
/* /*
* Technically we could use raw_spin_[un]lock_irq() here, but this can * Technically we could use raw_spin_[un]lock_irq() here, but this can
* be called in early boot if the cmpxchg() fast path is disabled * 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, ...@@ -1767,6 +1776,7 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock,
raw_spin_lock_irqsave(&lock->wait_lock, flags); raw_spin_lock_irqsave(&lock->wait_lock, flags);
ret = __rt_mutex_slowlock_locked(lock, ww_ctx, state); ret = __rt_mutex_slowlock_locked(lock, ww_ctx, state);
raw_spin_unlock_irqrestore(&lock->wait_lock, flags); raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
rt_mutex_post_schedule();
return ret; return ret;
} }
......
...@@ -71,6 +71,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb, ...@@ -71,6 +71,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,
struct rt_mutex_base *rtm = &rwb->rtmutex; struct rt_mutex_base *rtm = &rwb->rtmutex;
int ret; int ret;
rwbase_pre_schedule();
raw_spin_lock_irq(&rtm->wait_lock); raw_spin_lock_irq(&rtm->wait_lock);
/* /*
...@@ -125,6 +126,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb, ...@@ -125,6 +126,7 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,
rwbase_rtmutex_unlock(rtm); rwbase_rtmutex_unlock(rtm);
trace_contention_end(rwb, ret); trace_contention_end(rwb, ret);
rwbase_post_schedule();
return ret; return ret;
} }
...@@ -237,6 +239,8 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb, ...@@ -237,6 +239,8 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
/* Force readers into slow path */ /* Force readers into slow path */
atomic_sub(READER_BIAS, &rwb->readers); atomic_sub(READER_BIAS, &rwb->readers);
rwbase_pre_schedule();
raw_spin_lock_irqsave(&rtm->wait_lock, flags); raw_spin_lock_irqsave(&rtm->wait_lock, flags);
if (__rwbase_write_trylock(rwb)) if (__rwbase_write_trylock(rwb))
goto out_unlock; goto out_unlock;
...@@ -248,6 +252,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb, ...@@ -248,6 +252,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
if (rwbase_signal_pending_state(state, current)) { if (rwbase_signal_pending_state(state, current)) {
rwbase_restore_current_state(); rwbase_restore_current_state();
__rwbase_write_unlock(rwb, 0, flags); __rwbase_write_unlock(rwb, 0, flags);
rwbase_post_schedule();
trace_contention_end(rwb, -EINTR); trace_contention_end(rwb, -EINTR);
return -EINTR; return -EINTR;
} }
...@@ -266,6 +271,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb, ...@@ -266,6 +271,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
out_unlock: out_unlock:
raw_spin_unlock_irqrestore(&rtm->wait_lock, flags); raw_spin_unlock_irqrestore(&rtm->wait_lock, flags);
rwbase_post_schedule();
return 0; return 0;
} }
......
...@@ -1427,8 +1427,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem) ...@@ -1427,8 +1427,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
#define rwbase_signal_pending_state(state, current) \ #define rwbase_signal_pending_state(state, current) \
signal_pending_state(state, current) signal_pending_state(state, current)
#define rwbase_pre_schedule() \
rt_mutex_pre_schedule()
#define rwbase_schedule() \ #define rwbase_schedule() \
schedule() rt_mutex_schedule()
#define rwbase_post_schedule() \
rt_mutex_post_schedule()
#include "rwbase_rt.c" #include "rwbase_rt.c"
......
...@@ -184,9 +184,13 @@ static __always_inline int rwbase_rtmutex_trylock(struct rt_mutex_base *rtm) ...@@ -184,9 +184,13 @@ static __always_inline int rwbase_rtmutex_trylock(struct rt_mutex_base *rtm)
#define rwbase_signal_pending_state(state, current) (0) #define rwbase_signal_pending_state(state, current) (0)
#define rwbase_pre_schedule()
#define rwbase_schedule() \ #define rwbase_schedule() \
schedule_rtlock() schedule_rtlock()
#define rwbase_post_schedule()
#include "rwbase_rt.c" #include "rwbase_rt.c"
/* /*
* The common functions which get wrapped into the rwlock API. * The common functions which get wrapped into the rwlock API.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment