diff options
Diffstat (limited to 'kernel/futex.c')
| -rw-r--r-- | kernel/futex.c | 33 | 
1 files changed, 24 insertions, 9 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index b911adceb2c4..d73ef1f3e55d 100644 --- a/kernel/futex.c +++ b/kernel/futex.c  | |||
| @@ -150,7 +150,8 @@ static struct futex_hash_bucket *hash_futex(union futex_key *key) | |||
| 150 | */ | 150 | */ | 
| 151 | static inline int match_futex(union futex_key *key1, union futex_key *key2) | 151 | static inline int match_futex(union futex_key *key1, union futex_key *key2) | 
| 152 | { | 152 | { | 
| 153 | return (key1->both.word == key2->both.word | 153 | return (key1 && key2 | 
| 154 | && key1->both.word == key2->both.word | ||
| 154 | && key1->both.ptr == key2->both.ptr | 155 | && key1->both.ptr == key2->both.ptr | 
| 155 | && key1->both.offset == key2->both.offset); | 156 | && key1->both.offset == key2->both.offset); | 
| 156 | } | 157 | } | 
| @@ -303,8 +304,14 @@ void put_futex_key(int fshared, union futex_key *key) | |||
| 303 | */ | 304 | */ | 
| 304 | static int fault_in_user_writeable(u32 __user *uaddr) | 305 | static int fault_in_user_writeable(u32 __user *uaddr) | 
| 305 | { | 306 | { | 
| 306 | int ret = get_user_pages(current, current->mm, (unsigned long)uaddr, | 307 | struct mm_struct *mm = current->mm; | 
| 307 | 1, 1, 0, NULL, NULL); | 308 | int ret; | 
| 309 | |||
| 310 | down_read(&mm->mmap_sem); | ||
| 311 | ret = get_user_pages(current, mm, (unsigned long)uaddr, | ||
| 312 | 1, 1, 0, NULL, NULL); | ||
| 313 | up_read(&mm->mmap_sem); | ||
| 314 | |||
| 308 | return ret < 0 ? ret : 0; | 315 | return ret < 0 ? ret : 0; | 
| 309 | } | 316 | } | 
| 310 | 317 | ||
| @@ -916,8 +923,8 @@ retry: | |||
| 916 | hb1 = hash_futex(&key1); | 923 | hb1 = hash_futex(&key1); | 
| 917 | hb2 = hash_futex(&key2); | 924 | hb2 = hash_futex(&key2); | 
| 918 | 925 | ||
| 919 | double_lock_hb(hb1, hb2); | ||
| 920 | retry_private: | 926 | retry_private: | 
| 927 | double_lock_hb(hb1, hb2); | ||
| 921 | op_ret = futex_atomic_op_inuser(op, uaddr2); | 928 | op_ret = futex_atomic_op_inuser(op, uaddr2); | 
| 922 | if (unlikely(op_ret < 0)) { | 929 | if (unlikely(op_ret < 0)) { | 
| 923 | 930 | ||
| @@ -1028,7 +1035,6 @@ static inline | |||
| 1028 | void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, | 1035 | void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, | 
| 1029 | struct futex_hash_bucket *hb) | 1036 | struct futex_hash_bucket *hb) | 
| 1030 | { | 1037 | { | 
| 1031 | drop_futex_key_refs(&q->key); | ||
| 1032 | get_futex_key_refs(key); | 1038 | get_futex_key_refs(key); | 
| 1033 | q->key = *key; | 1039 | q->key = *key; | 
| 1034 | 1040 | ||
| @@ -1226,6 +1232,7 @@ retry_private: | |||
| 1226 | */ | 1232 | */ | 
| 1227 | if (ret == 1) { | 1233 | if (ret == 1) { | 
| 1228 | WARN_ON(pi_state); | 1234 | WARN_ON(pi_state); | 
| 1235 | drop_count++; | ||
| 1229 | task_count++; | 1236 | task_count++; | 
| 1230 | ret = get_futex_value_locked(&curval2, uaddr2); | 1237 | ret = get_futex_value_locked(&curval2, uaddr2); | 
| 1231 | if (!ret) | 1238 | if (!ret) | 
| @@ -1304,6 +1311,7 @@ retry_private: | |||
| 1304 | if (ret == 1) { | 1311 | if (ret == 1) { | 
| 1305 | /* We got the lock. */ | 1312 | /* We got the lock. */ | 
| 1306 | requeue_pi_wake_futex(this, &key2, hb2); | 1313 | requeue_pi_wake_futex(this, &key2, hb2); | 
| 1314 | drop_count++; | ||
| 1307 | continue; | 1315 | continue; | 
| 1308 | } else if (ret) { | 1316 | } else if (ret) { | 
| 1309 | /* -EDEADLK */ | 1317 | /* -EDEADLK */ | 
| @@ -1791,6 +1799,7 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
| 1791 | current->timer_slack_ns); | 1799 | current->timer_slack_ns); | 
| 1792 | } | 1800 | } | 
| 1793 | 1801 | ||
| 1802 | retry: | ||
| 1794 | /* Prepare to wait on uaddr. */ | 1803 | /* Prepare to wait on uaddr. */ | 
| 1795 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); | 1804 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); | 
| 1796 | if (ret) | 1805 | if (ret) | 
| @@ -1808,9 +1817,14 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
| 1808 | goto out_put_key; | 1817 | goto out_put_key; | 
| 1809 | 1818 | ||
| 1810 | /* | 1819 | /* | 
| 1811 | * We expect signal_pending(current), but another thread may | 1820 | * We expect signal_pending(current), but we might be the | 
| 1812 | * have handled it for us already. | 1821 | * victim of a spurious wakeup as well. | 
| 1813 | */ | 1822 | */ | 
| 1823 | if (!signal_pending(current)) { | ||
| 1824 | put_futex_key(fshared, &q.key); | ||
| 1825 | goto retry; | ||
| 1826 | } | ||
| 1827 | |||
| 1814 | ret = -ERESTARTSYS; | 1828 | ret = -ERESTARTSYS; | 
| 1815 | if (!abs_time) | 1829 | if (!abs_time) | 
| 1816 | goto out_put_key; | 1830 | goto out_put_key; | 
| @@ -2117,11 +2131,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, | |||
| 2117 | * Unqueue the futex_q and determine which it was. | 2131 | * Unqueue the futex_q and determine which it was. | 
| 2118 | */ | 2132 | */ | 
| 2119 | plist_del(&q->list, &q->list.plist); | 2133 | plist_del(&q->list, &q->list.plist); | 
| 2120 | drop_futex_key_refs(&q->key); | ||
| 2121 | 2134 | ||
| 2135 | /* Handle spurious wakeups gracefully */ | ||
| 2136 | ret = -EWOULDBLOCK; | ||
| 2122 | if (timeout && !timeout->task) | 2137 | if (timeout && !timeout->task) | 
| 2123 | ret = -ETIMEDOUT; | 2138 | ret = -ETIMEDOUT; | 
| 2124 | else | 2139 | else if (signal_pending(current)) | 
| 2125 | ret = -ERESTARTNOINTR; | 2140 | ret = -ERESTARTNOINTR; | 
| 2126 | } | 2141 | } | 
| 2127 | return ret; | 2142 | return ret; | 
