diff options
| -rw-r--r-- | kernel/futex.c | 51 |
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 | */ |
| 1105 | static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, | 1105 | static 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 |
