Skip to content

Commit 0fc4a93

Browse files
Sebastian Andrzej Siewiorrostedt
authored andcommitted
rtmutex: use a trylock for waiter lock in trylock
Mike Galbraith captered the following: | >torvalds#11 [ffff88017b243e90] _raw_spin_lock at ffffffff815d2596 | >torvalds#12 [ffff88017b243e90] rt_mutex_trylock at ffffffff815d15be | >torvalds#13 [ffff88017b243eb0] get_next_timer_interrupt at ffffffff81063b42 | >torvalds#14 [ffff88017b243f00] tick_nohz_stop_sched_tick at ffffffff810bd1fd | >torvalds#15 [ffff88017b243f70] tick_nohz_irq_exit at ffffffff810bd7d2 | >torvalds#16 [ffff88017b243f90] irq_exit at ffffffff8105b02d | >torvalds#17 [ffff88017b243fb0] reschedule_interrupt at ffffffff815db3dd | >--- <IRQ stack> --- | >torvalds#18 [ffff88017a2a9bc8] reschedule_interrupt at ffffffff815db3dd | > [exception RIP: task_blocks_on_rt_mutex+51] | >torvalds#19 [ffff88017a2a9ce0] rt_spin_lock_slowlock at ffffffff815d183c | >torvalds#20 [ffff88017a2a9da0] lock_timer_base.isra.35 at ffffffff81061cbf | >torvalds#21 [ffff88017a2a9dd0] schedule_timeout at ffffffff815cf1ce | >torvalds#22 [ffff88017a2a9e50] rcu_gp_kthread at ffffffff810f9bbb | >torvalds#23 [ffff88017a2a9ed0] kthread at ffffffff810796d5 | >torvalds#24 [ffff88017a2a9f50] ret_from_fork at ffffffff815da04c lock_timer_base() does a try_lock() which deadlocks on the waiter lock not the lock itself. This patch takes the waiter_lock with trylock so it should work from interrupt context as well. If the fastpath doesn't work and the waiter_lock itself is taken then it seems that the lock itself taken. This patch also adds a "rt_spin_try_unlock" to keep lockdep happy. If we managed to take the wait_lock in the first place we should also be able to take it in the unlock path. Cc: [email protected] Reported-by: Mike Galbraith <[email protected]> Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
1 parent 574f2e7 commit 0fc4a93

File tree

3 files changed

+29
-5
lines changed

3 files changed

+29
-5
lines changed

include/linux/spinlock_rt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern void __lockfunc rt_spin_lock(spinlock_t *lock);
2222
extern unsigned long __lockfunc rt_spin_lock_trace_flags(spinlock_t *lock);
2323
extern void __lockfunc rt_spin_lock_nested(spinlock_t *lock, int subclass);
2424
extern void __lockfunc rt_spin_unlock(spinlock_t *lock);
25+
extern void __lockfunc rt_spin_unlock_after_trylock_in_irq(spinlock_t *lock);
2526
extern void __lockfunc rt_spin_unlock_wait(spinlock_t *lock);
2627
extern int __lockfunc rt_spin_trylock_irqsave(spinlock_t *lock, unsigned long *flags);
2728
extern int __lockfunc rt_spin_trylock_bh(spinlock_t *lock);

kernel/rtmutex.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -802,10 +802,8 @@ static void noinline __sched rt_spin_lock_slowlock(struct rt_mutex *lock)
802802
/*
803803
* Slow path to release a rt_mutex spin_lock style
804804
*/
805-
static void noinline __sched rt_spin_lock_slowunlock(struct rt_mutex *lock)
805+
static void __sched __rt_spin_lock_slowunlock(struct rt_mutex *lock)
806806
{
807-
raw_spin_lock(&lock->wait_lock);
808-
809807
debug_rt_mutex_unlock(lock);
810808

811809
rt_mutex_deadlock_account_unlock(current);
@@ -824,6 +822,23 @@ static void noinline __sched rt_spin_lock_slowunlock(struct rt_mutex *lock)
824822
rt_mutex_adjust_prio(current);
825823
}
826824

825+
static void noinline __sched rt_spin_lock_slowunlock(struct rt_mutex *lock)
826+
{
827+
raw_spin_lock(&lock->wait_lock);
828+
__rt_spin_lock_slowunlock(lock);
829+
}
830+
831+
static void noinline __sched rt_spin_lock_slowunlock_hirq(struct rt_mutex *lock)
832+
{
833+
int ret;
834+
835+
do {
836+
ret = raw_spin_trylock(&lock->wait_lock);
837+
} while (!ret);
838+
839+
__rt_spin_lock_slowunlock(lock);
840+
}
841+
827842
void __lockfunc rt_spin_lock(spinlock_t *lock)
828843
{
829844
rt_spin_lock_fastlock(&lock->lock, rt_spin_lock_slowlock);
@@ -854,6 +869,13 @@ void __lockfunc rt_spin_unlock(spinlock_t *lock)
854869
}
855870
EXPORT_SYMBOL(rt_spin_unlock);
856871

872+
void __lockfunc rt_spin_unlock_after_trylock_in_irq(spinlock_t *lock)
873+
{
874+
/* NOTE: we always pass in '1' for nested, for simplicity */
875+
spin_release(&lock->dep_map, 1, _RET_IP_);
876+
rt_spin_lock_fastunlock(&lock->lock, rt_spin_lock_slowunlock_hirq);
877+
}
878+
857879
void __lockfunc __rt_spin_unlock(struct rt_mutex *lock)
858880
{
859881
rt_spin_lock_fastunlock(lock, rt_spin_lock_slowunlock);
@@ -1057,7 +1079,8 @@ rt_mutex_slowtrylock(struct rt_mutex *lock)
10571079
{
10581080
int ret = 0;
10591081

1060-
raw_spin_lock(&lock->wait_lock);
1082+
if (!raw_spin_trylock(&lock->wait_lock))
1083+
return ret;
10611084
init_lists(lock);
10621085

10631086
if (likely(rt_mutex_owner(lock) != current)) {

kernel/timer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,7 @@ unsigned long get_next_timer_interrupt(unsigned long now)
14001400
expires = base->next_timer;
14011401
}
14021402
#ifdef CONFIG_PREEMPT_RT_FULL
1403-
rt_spin_unlock(&base->lock);
1403+
rt_spin_unlock_after_trylock_in_irq(&base->lock);
14041404
#else
14051405
spin_unlock(&base->lock);
14061406
#endif

0 commit comments

Comments
 (0)