diff options
Diffstat (limited to 'kernel/futex.c')
| -rw-r--r-- | kernel/futex.c | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 3717e7b306e0..19eb089ca003 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
| @@ -716,7 +716,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, | |||
| 716 | struct futex_pi_state **ps, | 716 | struct futex_pi_state **ps, |
| 717 | struct task_struct *task, int set_waiters) | 717 | struct task_struct *task, int set_waiters) |
| 718 | { | 718 | { |
| 719 | int lock_taken, ret, ownerdied = 0; | 719 | int lock_taken, ret, force_take = 0; |
| 720 | u32 uval, newval, curval, vpid = task_pid_vnr(task); | 720 | u32 uval, newval, curval, vpid = task_pid_vnr(task); |
| 721 | 721 | ||
| 722 | retry: | 722 | retry: |
| @@ -755,17 +755,15 @@ retry: | |||
| 755 | newval = curval | FUTEX_WAITERS; | 755 | newval = curval | FUTEX_WAITERS; |
| 756 | 756 | ||
| 757 | /* | 757 | /* |
| 758 | * There are two cases, where a futex might have no owner (the | 758 | * Should we force take the futex? See below. |
| 759 | * owner TID is 0): OWNER_DIED. We take over the futex in this | ||
| 760 | * case. We also do an unconditional take over, when the owner | ||
| 761 | * of the futex died. | ||
| 762 | * | ||
| 763 | * This is safe as we are protected by the hash bucket lock ! | ||
| 764 | */ | 759 | */ |
| 765 | if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) { | 760 | if (unlikely(force_take)) { |
| 766 | /* Keep the OWNER_DIED bit */ | 761 | /* |
| 762 | * Keep the OWNER_DIED and the WAITERS bit and set the | ||
| 763 | * new TID value. | ||
| 764 | */ | ||
| 767 | newval = (curval & ~FUTEX_TID_MASK) | vpid; | 765 | newval = (curval & ~FUTEX_TID_MASK) | vpid; |
| 768 | ownerdied = 0; | 766 | force_take = 0; |
| 769 | lock_taken = 1; | 767 | lock_taken = 1; |
| 770 | } | 768 | } |
| 771 | 769 | ||
| @@ -775,7 +773,7 @@ retry: | |||
| 775 | goto retry; | 773 | goto retry; |
| 776 | 774 | ||
| 777 | /* | 775 | /* |
| 778 | * We took the lock due to owner died take over. | 776 | * We took the lock due to forced take over. |
| 779 | */ | 777 | */ |
| 780 | if (unlikely(lock_taken)) | 778 | if (unlikely(lock_taken)) |
| 781 | return 1; | 779 | return 1; |
| @@ -790,20 +788,25 @@ retry: | |||
| 790 | switch (ret) { | 788 | switch (ret) { |
| 791 | case -ESRCH: | 789 | case -ESRCH: |
| 792 | /* | 790 | /* |
| 793 | * No owner found for this futex. Check if the | 791 | * We failed to find an owner for this |
| 794 | * OWNER_DIED bit is set to figure out whether | 792 | * futex. So we have no pi_state to block |
| 795 | * this is a robust futex or not. | 793 | * on. This can happen in two cases: |
| 794 | * | ||
| 795 | * 1) The owner died | ||
| 796 | * 2) A stale FUTEX_WAITERS bit | ||
| 797 | * | ||
| 798 | * Re-read the futex value. | ||
| 796 | */ | 799 | */ |
| 797 | if (get_futex_value_locked(&curval, uaddr)) | 800 | if (get_futex_value_locked(&curval, uaddr)) |
| 798 | return -EFAULT; | 801 | return -EFAULT; |
| 799 | 802 | ||
| 800 | /* | 803 | /* |
| 801 | * We simply start over in case of a robust | 804 | * If the owner died or we have a stale |
| 802 | * futex. The code above will take the futex | 805 | * WAITERS bit the owner TID in the user space |
| 803 | * and return happy. | 806 | * futex is 0. |
| 804 | */ | 807 | */ |
| 805 | if (curval & FUTEX_OWNER_DIED) { | 808 | if (!(curval & FUTEX_TID_MASK)) { |
| 806 | ownerdied = 1; | 809 | force_take = 1; |
| 807 | goto retry; | 810 | goto retry; |
| 808 | } | 811 | } |
| 809 | default: | 812 | default: |
| @@ -840,6 +843,9 @@ static void wake_futex(struct futex_q *q) | |||
| 840 | { | 843 | { |
| 841 | struct task_struct *p = q->task; | 844 | struct task_struct *p = q->task; |
| 842 | 845 | ||
| 846 | if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n")) | ||
| 847 | return; | ||
| 848 | |||
| 843 | /* | 849 | /* |
| 844 | * We set q->lock_ptr = NULL _before_ we wake up the task. If | 850 | * We set q->lock_ptr = NULL _before_ we wake up the task. If |
| 845 | * a non-futex wake up happens on another CPU then the task | 851 | * a non-futex wake up happens on another CPU then the task |
| @@ -1075,6 +1081,10 @@ retry_private: | |||
| 1075 | 1081 | ||
| 1076 | plist_for_each_entry_safe(this, next, head, list) { | 1082 | plist_for_each_entry_safe(this, next, head, list) { |
| 1077 | if (match_futex (&this->key, &key1)) { | 1083 | if (match_futex (&this->key, &key1)) { |
| 1084 | if (this->pi_state || this->rt_waiter) { | ||
| 1085 | ret = -EINVAL; | ||
| 1086 | goto out_unlock; | ||
| 1087 | } | ||
| 1078 | wake_futex(this); | 1088 | wake_futex(this); |
| 1079 | if (++ret >= nr_wake) | 1089 | if (++ret >= nr_wake) |
| 1080 | break; | 1090 | break; |
| @@ -1087,6 +1097,10 @@ retry_private: | |||
| 1087 | op_ret = 0; | 1097 | op_ret = 0; |
| 1088 | plist_for_each_entry_safe(this, next, head, list) { | 1098 | plist_for_each_entry_safe(this, next, head, list) { |
| 1089 | if (match_futex (&this->key, &key2)) { | 1099 | if (match_futex (&this->key, &key2)) { |
| 1100 | if (this->pi_state || this->rt_waiter) { | ||
| 1101 | ret = -EINVAL; | ||
| 1102 | goto out_unlock; | ||
| 1103 | } | ||
| 1090 | wake_futex(this); | 1104 | wake_futex(this); |
| 1091 | if (++op_ret >= nr_wake2) | 1105 | if (++op_ret >= nr_wake2) |
| 1092 | break; | 1106 | break; |
| @@ -1095,6 +1109,7 @@ retry_private: | |||
| 1095 | ret += op_ret; | 1109 | ret += op_ret; |
| 1096 | } | 1110 | } |
| 1097 | 1111 | ||
| 1112 | out_unlock: | ||
| 1098 | double_unlock_hb(hb1, hb2); | 1113 | double_unlock_hb(hb1, hb2); |
| 1099 | out_put_keys: | 1114 | out_put_keys: |
| 1100 | put_futex_key(&key2); | 1115 | put_futex_key(&key2); |
| @@ -1384,9 +1399,13 @@ retry_private: | |||
| 1384 | /* | 1399 | /* |
| 1385 | * FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always | 1400 | * FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always |
| 1386 | * be paired with each other and no other futex ops. | 1401 | * be paired with each other and no other futex ops. |
| 1402 | * | ||
| 1403 | * We should never be requeueing a futex_q with a pi_state, | ||
| 1404 | * which is awaiting a futex_unlock_pi(). | ||
| 1387 | */ | 1405 | */ |
| 1388 | if ((requeue_pi && !this->rt_waiter) || | 1406 | if ((requeue_pi && !this->rt_waiter) || |
| 1389 | (!requeue_pi && this->rt_waiter)) { | 1407 | (!requeue_pi && this->rt_waiter) || |
| 1408 | this->pi_state) { | ||
| 1390 | ret = -EINVAL; | 1409 | ret = -EINVAL; |
| 1391 | break; | 1410 | break; |
| 1392 | } | 1411 | } |
