futex: workaround migrate_disable/enable in different context

migrate_enable() invokes __schedule() and it expects a preempt count of one.
Holding a raw_spinlock_t with disabled interrupts should not allow scheduling.

These little hacks ensure that we don't schedule while we lock the hb lockwith
interrupts enabled and unlock it with interrupts disabled.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
[XXX: As per PeterZ suggesstion
	set_thread_flag(TIF_NEED_RESCHED); preempt_fold_need_resched()
 would trigger a scheduler invocation on the last preempt_enable() which in
 turn would allow to drop this.
]
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
This commit is contained in:
Thomas Gleixner 2017-03-08 14:23:35 +01:00 committed by Alibek Omarov
parent 6ff7d19cf2
commit c8ff2f06be
1 changed files with 18 additions and 0 deletions

View File

@ -3014,6 +3014,14 @@ retry_private:
* before __rt_mutex_start_proxy_lock() is done.
*/
raw_spin_lock_irq(&q.pi_state->pi_mutex.wait_lock);
/*
* the migrate_disable() here disables migration in the in_atomic() fast
* path which is enabled again in the following spin_unlock(). We have
* one migrate_disable() pending in the slow-path which is reversed
* after the raw_spin_unlock_irq() where we leave the atomic context.
*/
migrate_disable();
spin_unlock(q.lock_ptr);
/*
* __rt_mutex_start_proxy_lock() unconditionally enqueues the @rt_waiter
@ -3022,6 +3030,7 @@ retry_private:
*/
ret = __rt_mutex_start_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter, current);
raw_spin_unlock_irq(&q.pi_state->pi_mutex.wait_lock);
migrate_enable();
if (ret) {
if (ret == 1)
@ -3156,10 +3165,19 @@ retry:
* rt_waiter. Also see the WARN in wake_futex_pi().
*/
raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
/*
* Magic trickery for now to make the RT migrate disable
* logic happy. The following spin_unlock() happens with
* interrupts disabled so the internal migrate_enable()
* won't undo the migrate_disable() which was issued when
* locking hb->lock.
*/
migrate_disable();
spin_unlock(&hb->lock);
/* drops pi_state->pi_mutex.wait_lock */
ret = wake_futex_pi(uaddr, uval, pi_state);
migrate_enable();
put_pi_state(pi_state);