diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index b911adceb2c4..642f3bbaacc7 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 | } |
@@ -916,8 +917,8 @@ retry: | |||
916 | hb1 = hash_futex(&key1); | 917 | hb1 = hash_futex(&key1); |
917 | hb2 = hash_futex(&key2); | 918 | hb2 = hash_futex(&key2); |
918 | 919 | ||
919 | double_lock_hb(hb1, hb2); | ||
920 | retry_private: | 920 | retry_private: |
921 | double_lock_hb(hb1, hb2); | ||
921 | op_ret = futex_atomic_op_inuser(op, uaddr2); | 922 | op_ret = futex_atomic_op_inuser(op, uaddr2); |
922 | if (unlikely(op_ret < 0)) { | 923 | if (unlikely(op_ret < 0)) { |
923 | 924 | ||
@@ -1028,7 +1029,6 @@ static inline | |||
1028 | void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, | 1029 | void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, |
1029 | struct futex_hash_bucket *hb) | 1030 | struct futex_hash_bucket *hb) |
1030 | { | 1031 | { |
1031 | drop_futex_key_refs(&q->key); | ||
1032 | get_futex_key_refs(key); | 1032 | get_futex_key_refs(key); |
1033 | q->key = *key; | 1033 | q->key = *key; |
1034 | 1034 | ||
@@ -1226,6 +1226,7 @@ retry_private: | |||
1226 | */ | 1226 | */ |
1227 | if (ret == 1) { | 1227 | if (ret == 1) { |
1228 | WARN_ON(pi_state); | 1228 | WARN_ON(pi_state); |
1229 | drop_count++; | ||
1229 | task_count++; | 1230 | task_count++; |
1230 | ret = get_futex_value_locked(&curval2, uaddr2); | 1231 | ret = get_futex_value_locked(&curval2, uaddr2); |
1231 | if (!ret) | 1232 | if (!ret) |
@@ -1304,6 +1305,7 @@ retry_private: | |||
1304 | if (ret == 1) { | 1305 | if (ret == 1) { |
1305 | /* We got the lock. */ | 1306 | /* We got the lock. */ |
1306 | requeue_pi_wake_futex(this, &key2, hb2); | 1307 | requeue_pi_wake_futex(this, &key2, hb2); |
1308 | drop_count++; | ||
1307 | continue; | 1309 | continue; |
1308 | } else if (ret) { | 1310 | } else if (ret) { |
1309 | /* -EDEADLK */ | 1311 | /* -EDEADLK */ |
@@ -1791,6 +1793,7 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
1791 | current->timer_slack_ns); | 1793 | current->timer_slack_ns); |
1792 | } | 1794 | } |
1793 | 1795 | ||
1796 | retry: | ||
1794 | /* Prepare to wait on uaddr. */ | 1797 | /* Prepare to wait on uaddr. */ |
1795 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); | 1798 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); |
1796 | if (ret) | 1799 | if (ret) |
@@ -1808,9 +1811,14 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
1808 | goto out_put_key; | 1811 | goto out_put_key; |
1809 | 1812 | ||
1810 | /* | 1813 | /* |
1811 | * We expect signal_pending(current), but another thread may | 1814 | * We expect signal_pending(current), but we might be the |
1812 | * have handled it for us already. | 1815 | * victim of a spurious wakeup as well. |
1813 | */ | 1816 | */ |
1817 | if (!signal_pending(current)) { | ||
1818 | put_futex_key(fshared, &q.key); | ||
1819 | goto retry; | ||
1820 | } | ||
1821 | |||
1814 | ret = -ERESTARTSYS; | 1822 | ret = -ERESTARTSYS; |
1815 | if (!abs_time) | 1823 | if (!abs_time) |
1816 | goto out_put_key; | 1824 | goto out_put_key; |
@@ -2117,11 +2125,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, | |||
2117 | * Unqueue the futex_q and determine which it was. | 2125 | * Unqueue the futex_q and determine which it was. |
2118 | */ | 2126 | */ |
2119 | plist_del(&q->list, &q->list.plist); | 2127 | plist_del(&q->list, &q->list.plist); |
2120 | drop_futex_key_refs(&q->key); | ||
2121 | 2128 | ||
2129 | /* Handle spurious wakeups gracefully */ | ||
2130 | ret = -EAGAIN; | ||
2122 | if (timeout && !timeout->task) | 2131 | if (timeout && !timeout->task) |
2123 | ret = -ETIMEDOUT; | 2132 | ret = -ETIMEDOUT; |
2124 | else | 2133 | else if (signal_pending(current)) |
2125 | ret = -ERESTARTNOINTR; | 2134 | ret = -ERESTARTNOINTR; |
2126 | } | 2135 | } |
2127 | return ret; | 2136 | return ret; |
@@ -2199,6 +2208,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, | |||
2199 | debug_rt_mutex_init_waiter(&rt_waiter); | 2208 | debug_rt_mutex_init_waiter(&rt_waiter); |
2200 | rt_waiter.task = NULL; | 2209 | rt_waiter.task = NULL; |
2201 | 2210 | ||
2211 | retry: | ||
2202 | key2 = FUTEX_KEY_INIT; | 2212 | key2 = FUTEX_KEY_INIT; |
2203 | ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE); | 2213 | ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE); |
2204 | if (unlikely(ret != 0)) | 2214 | if (unlikely(ret != 0)) |
@@ -2293,6 +2303,9 @@ out_put_keys: | |||
2293 | out_key2: | 2303 | out_key2: |
2294 | put_futex_key(fshared, &key2); | 2304 | put_futex_key(fshared, &key2); |
2295 | 2305 | ||
2306 | /* Spurious wakeup ? */ | ||
2307 | if (ret == -EAGAIN) | ||
2308 | goto retry; | ||
2296 | out: | 2309 | out: |
2297 | if (to) { | 2310 | if (to) { |
2298 | hrtimer_cancel(&to->timer); | 2311 | hrtimer_cancel(&to->timer); |