mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull locking fixes from Thomas Gleixner: "Two fixes for locking: - Plug a hole the pi_stat->owner serialization which was changed recently and failed to fixup two usage sites. - Prevent reordering of the rwsem_has_spinner() check vs the decrement of rwsem count in up_write() which causes a missed wakeup" * 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: locking/rwsem-xadd: Fix missed wakeup due to reordering of load futex: Fix pi_state->owner serialization
This commit is contained in:
commit
1de47f3cb7
@ -821,8 +821,6 @@ static void get_pi_state(struct futex_pi_state *pi_state)
|
||||
/*
|
||||
* Drops a reference to the pi_state object and frees or caches it
|
||||
* when the last reference is gone.
|
||||
*
|
||||
* Must be called with the hb lock held.
|
||||
*/
|
||||
static void put_pi_state(struct futex_pi_state *pi_state)
|
||||
{
|
||||
@ -837,16 +835,22 @@ static void put_pi_state(struct futex_pi_state *pi_state)
|
||||
* and has cleaned up the pi_state already
|
||||
*/
|
||||
if (pi_state->owner) {
|
||||
raw_spin_lock_irq(&pi_state->owner->pi_lock);
|
||||
list_del_init(&pi_state->list);
|
||||
raw_spin_unlock_irq(&pi_state->owner->pi_lock);
|
||||
struct task_struct *owner;
|
||||
|
||||
rt_mutex_proxy_unlock(&pi_state->pi_mutex, pi_state->owner);
|
||||
raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
|
||||
owner = pi_state->owner;
|
||||
if (owner) {
|
||||
raw_spin_lock(&owner->pi_lock);
|
||||
list_del_init(&pi_state->list);
|
||||
raw_spin_unlock(&owner->pi_lock);
|
||||
}
|
||||
rt_mutex_proxy_unlock(&pi_state->pi_mutex, owner);
|
||||
raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
|
||||
}
|
||||
|
||||
if (current->pi_state_cache)
|
||||
if (current->pi_state_cache) {
|
||||
kfree(pi_state);
|
||||
else {
|
||||
} else {
|
||||
/*
|
||||
* pi_state->list is already empty.
|
||||
* clear pi_state->owner.
|
||||
@ -907,13 +911,14 @@ void exit_pi_state_list(struct task_struct *curr)
|
||||
raw_spin_unlock_irq(&curr->pi_lock);
|
||||
|
||||
spin_lock(&hb->lock);
|
||||
|
||||
raw_spin_lock_irq(&curr->pi_lock);
|
||||
raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
|
||||
raw_spin_lock(&curr->pi_lock);
|
||||
/*
|
||||
* We dropped the pi-lock, so re-check whether this
|
||||
* task still owns the PI-state:
|
||||
*/
|
||||
if (head->next != next) {
|
||||
raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
|
||||
spin_unlock(&hb->lock);
|
||||
continue;
|
||||
}
|
||||
@ -922,9 +927,10 @@ void exit_pi_state_list(struct task_struct *curr)
|
||||
WARN_ON(list_empty(&pi_state->list));
|
||||
list_del_init(&pi_state->list);
|
||||
pi_state->owner = NULL;
|
||||
raw_spin_unlock_irq(&curr->pi_lock);
|
||||
raw_spin_unlock(&curr->pi_lock);
|
||||
|
||||
get_pi_state(pi_state);
|
||||
raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
|
||||
spin_unlock(&hb->lock);
|
||||
|
||||
rt_mutex_futex_unlock(&pi_state->pi_mutex);
|
||||
@ -1208,6 +1214,10 @@ static int attach_to_pi_owner(u32 uval, union futex_key *key,
|
||||
|
||||
WARN_ON(!list_empty(&pi_state->list));
|
||||
list_add(&pi_state->list, &p->pi_state_list);
|
||||
/*
|
||||
* Assignment without holding pi_state->pi_mutex.wait_lock is safe
|
||||
* because there is no concurrency as the object is not published yet.
|
||||
*/
|
||||
pi_state->owner = p;
|
||||
raw_spin_unlock_irq(&p->pi_lock);
|
||||
|
||||
@ -2878,6 +2888,7 @@ retry:
|
||||
raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
|
||||
spin_unlock(&hb->lock);
|
||||
|
||||
/* drops pi_state->pi_mutex.wait_lock */
|
||||
ret = wake_futex_pi(uaddr, uval, pi_state);
|
||||
|
||||
put_pi_state(pi_state);
|
||||
|
@ -612,6 +612,33 @@ struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
|
||||
unsigned long flags;
|
||||
DEFINE_WAKE_Q(wake_q);
|
||||
|
||||
/*
|
||||
* __rwsem_down_write_failed_common(sem)
|
||||
* rwsem_optimistic_spin(sem)
|
||||
* osq_unlock(sem->osq)
|
||||
* ...
|
||||
* atomic_long_add_return(&sem->count)
|
||||
*
|
||||
* - VS -
|
||||
*
|
||||
* __up_write()
|
||||
* if (atomic_long_sub_return_release(&sem->count) < 0)
|
||||
* rwsem_wake(sem)
|
||||
* osq_is_locked(&sem->osq)
|
||||
*
|
||||
* And __up_write() must observe !osq_is_locked() when it observes the
|
||||
* atomic_long_add_return() in order to not miss a wakeup.
|
||||
*
|
||||
* This boils down to:
|
||||
*
|
||||
* [S.rel] X = 1 [RmW] r0 = (Y += 0)
|
||||
* MB RMB
|
||||
* [RmW] Y += 1 [L] r1 = X
|
||||
*
|
||||
* exists (r0=1 /\ r1=0)
|
||||
*/
|
||||
smp_rmb();
|
||||
|
||||
/*
|
||||
* If a spinner is present, it is not necessary to do the wakeup.
|
||||
* Try to do wakeup only if the trylock succeeds to minimize
|
||||
|
Loading…
Reference in New Issue
Block a user