aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/futex.c51
1 files changed, 41 insertions, 10 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 172a1aeeafdb..db9824de8bf0 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1097,15 +1097,15 @@ static void unqueue_me_pi(struct futex_q *q)
1097} 1097}
1098 1098
1099/* 1099/*
1100 * Fixup the pi_state owner with current. 1100 * Fixup the pi_state owner with the new owner.
1101 * 1101 *
1102 * Must be called with hash bucket lock held and mm->sem held for non 1102 * Must be called with hash bucket lock held and mm->sem held for non
1103 * private futexes. 1103 * private futexes.
1104 */ 1104 */
1105static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, 1105static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
1106 struct task_struct *curr) 1106 struct task_struct *newowner)
1107{ 1107{
1108 u32 newtid = task_pid_vnr(curr) | FUTEX_WAITERS; 1108 u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
1109 struct futex_pi_state *pi_state = q->pi_state; 1109 struct futex_pi_state *pi_state = q->pi_state;
1110 u32 uval, curval, newval; 1110 u32 uval, curval, newval;
1111 int ret; 1111 int ret;
@@ -1119,12 +1119,12 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
1119 } else 1119 } else
1120 newtid |= FUTEX_OWNER_DIED; 1120 newtid |= FUTEX_OWNER_DIED;
1121 1121
1122 pi_state->owner = curr; 1122 pi_state->owner = newowner;
1123 1123
1124 spin_lock_irq(&curr->pi_lock); 1124 spin_lock_irq(&newowner->pi_lock);
1125 WARN_ON(!list_empty(&pi_state->list)); 1125 WARN_ON(!list_empty(&pi_state->list));
1126 list_add(&pi_state->list, &curr->pi_state_list); 1126 list_add(&pi_state->list, &newowner->pi_state_list);
1127 spin_unlock_irq(&curr->pi_lock); 1127 spin_unlock_irq(&newowner->pi_lock);
1128 1128
1129 /* 1129 /*
1130 * We own it, so we have to replace the pending owner 1130 * We own it, so we have to replace the pending owner
@@ -1508,9 +1508,40 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
1508 * when we were on the way back before we locked the 1508 * when we were on the way back before we locked the
1509 * hash bucket. 1509 * hash bucket.
1510 */ 1510 */
1511 if (q.pi_state->owner == curr && 1511 if (q.pi_state->owner == curr) {
1512 rt_mutex_trylock(&q.pi_state->pi_mutex)) { 1512 /*
1513 ret = 0; 1513 * Try to get the rt_mutex now. This might
1514 * fail as some other task acquired the
1515 * rt_mutex after we removed ourself from the
1516 * rt_mutex waiters list.
1517 */
1518 if (rt_mutex_trylock(&q.pi_state->pi_mutex))
1519 ret = 0;
1520 else {
1521 /*
1522 * pi_state is incorrect, some other
1523 * task did a lock steal and we
1524 * returned due to timeout or signal
1525 * without taking the rt_mutex. Too
1526 * late. We can access the
1527 * rt_mutex_owner without locking, as
1528 * the other task is now blocked on
1529 * the hash bucket lock. Fix the state
1530 * up.
1531 */
1532 struct task_struct *owner;
1533 int res;
1534
1535 owner = rt_mutex_owner(&q.pi_state->pi_mutex);
1536 res = fixup_pi_state_owner(uaddr, &q, owner);
1537
1538 WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) !=
1539 owner);
1540
1541 /* propagate -EFAULT, if the fixup failed */
1542 if (res)
1543 ret = res;
1544 }
1514 } else { 1545 } else {
1515 /* 1546 /*
1516 * Paranoia check. If we did not take the lock 1547 * Paranoia check. If we did not take the lock