diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 2579e407ff67..f9984c363e9a 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -1090,9 +1090,11 @@ static void __unqueue_futex(struct futex_q *q) | |||
1090 | 1090 | ||
1091 | /* | 1091 | /* |
1092 | * The hash bucket lock must be held when this is called. | 1092 | * The hash bucket lock must be held when this is called. |
1093 | * Afterwards, the futex_q must not be accessed. | 1093 | * Afterwards, the futex_q must not be accessed. Callers |
1094 | * must ensure to later call wake_up_q() for the actual | ||
1095 | * wakeups to occur. | ||
1094 | */ | 1096 | */ |
1095 | static void wake_futex(struct futex_q *q) | 1097 | static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q) |
1096 | { | 1098 | { |
1097 | struct task_struct *p = q->task; | 1099 | struct task_struct *p = q->task; |
1098 | 1100 | ||
@@ -1100,14 +1102,10 @@ static void wake_futex(struct futex_q *q) | |||
1100 | return; | 1102 | return; |
1101 | 1103 | ||
1102 | /* | 1104 | /* |
1103 | * We set q->lock_ptr = NULL _before_ we wake up the task. If | 1105 | * Queue the task for later wakeup for after we've released |
1104 | * a non-futex wake up happens on another CPU then the task | 1106 | * the hb->lock. wake_q_add() grabs reference to p. |
1105 | * might exit and p would dereference a non-existing task | ||
1106 | * struct. Prevent this by holding a reference on p across the | ||
1107 | * wake up. | ||
1108 | */ | 1107 | */ |
1109 | get_task_struct(p); | 1108 | wake_q_add(wake_q, p); |
1110 | |||
1111 | __unqueue_futex(q); | 1109 | __unqueue_futex(q); |
1112 | /* | 1110 | /* |
1113 | * The waiting task can free the futex_q as soon as | 1111 | * The waiting task can free the futex_q as soon as |
@@ -1117,9 +1115,6 @@ static void wake_futex(struct futex_q *q) | |||
1117 | */ | 1115 | */ |
1118 | smp_wmb(); | 1116 | smp_wmb(); |
1119 | q->lock_ptr = NULL; | 1117 | q->lock_ptr = NULL; |
1120 | |||
1121 | wake_up_state(p, TASK_NORMAL); | ||
1122 | put_task_struct(p); | ||
1123 | } | 1118 | } |
1124 | 1119 | ||
1125 | static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) | 1120 | static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) |
@@ -1217,6 +1212,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) | |||
1217 | struct futex_q *this, *next; | 1212 | struct futex_q *this, *next; |
1218 | union futex_key key = FUTEX_KEY_INIT; | 1213 | union futex_key key = FUTEX_KEY_INIT; |
1219 | int ret; | 1214 | int ret; |
1215 | WAKE_Q(wake_q); | ||
1220 | 1216 | ||
1221 | if (!bitset) | 1217 | if (!bitset) |
1222 | return -EINVAL; | 1218 | return -EINVAL; |
@@ -1244,13 +1240,14 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) | |||
1244 | if (!(this->bitset & bitset)) | 1240 | if (!(this->bitset & bitset)) |
1245 | continue; | 1241 | continue; |
1246 | 1242 | ||
1247 | wake_futex(this); | 1243 | mark_wake_futex(&wake_q, this); |
1248 | if (++ret >= nr_wake) | 1244 | if (++ret >= nr_wake) |
1249 | break; | 1245 | break; |
1250 | } | 1246 | } |
1251 | } | 1247 | } |
1252 | 1248 | ||
1253 | spin_unlock(&hb->lock); | 1249 | spin_unlock(&hb->lock); |
1250 | wake_up_q(&wake_q); | ||
1254 | out_put_key: | 1251 | out_put_key: |
1255 | put_futex_key(&key); | 1252 | put_futex_key(&key); |
1256 | out: | 1253 | out: |
@@ -1269,6 +1266,7 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2, | |||
1269 | struct futex_hash_bucket *hb1, *hb2; | 1266 | struct futex_hash_bucket *hb1, *hb2; |
1270 | struct futex_q *this, *next; | 1267 | struct futex_q *this, *next; |
1271 | int ret, op_ret; | 1268 | int ret, op_ret; |
1269 | WAKE_Q(wake_q); | ||
1272 | 1270 | ||
1273 | retry: | 1271 | retry: |
1274 | ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); | 1272 | ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); |
@@ -1320,7 +1318,7 @@ retry_private: | |||
1320 | ret = -EINVAL; | 1318 | ret = -EINVAL; |
1321 | goto out_unlock; | 1319 | goto out_unlock; |
1322 | } | 1320 | } |
1323 | wake_futex(this); | 1321 | mark_wake_futex(&wake_q, this); |
1324 | if (++ret >= nr_wake) | 1322 | if (++ret >= nr_wake) |
1325 | break; | 1323 | break; |
1326 | } | 1324 | } |
@@ -1334,7 +1332,7 @@ retry_private: | |||
1334 | ret = -EINVAL; | 1332 | ret = -EINVAL; |
1335 | goto out_unlock; | 1333 | goto out_unlock; |
1336 | } | 1334 | } |
1337 | wake_futex(this); | 1335 | mark_wake_futex(&wake_q, this); |
1338 | if (++op_ret >= nr_wake2) | 1336 | if (++op_ret >= nr_wake2) |
1339 | break; | 1337 | break; |
1340 | } | 1338 | } |
@@ -1344,6 +1342,7 @@ retry_private: | |||
1344 | 1342 | ||
1345 | out_unlock: | 1343 | out_unlock: |
1346 | double_unlock_hb(hb1, hb2); | 1344 | double_unlock_hb(hb1, hb2); |
1345 | wake_up_q(&wake_q); | ||
1347 | out_put_keys: | 1346 | out_put_keys: |
1348 | put_futex_key(&key2); | 1347 | put_futex_key(&key2); |
1349 | out_put_key1: | 1348 | out_put_key1: |
@@ -1503,6 +1502,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, | |||
1503 | struct futex_pi_state *pi_state = NULL; | 1502 | struct futex_pi_state *pi_state = NULL; |
1504 | struct futex_hash_bucket *hb1, *hb2; | 1503 | struct futex_hash_bucket *hb1, *hb2; |
1505 | struct futex_q *this, *next; | 1504 | struct futex_q *this, *next; |
1505 | WAKE_Q(wake_q); | ||
1506 | 1506 | ||
1507 | if (requeue_pi) { | 1507 | if (requeue_pi) { |
1508 | /* | 1508 | /* |
@@ -1679,7 +1679,7 @@ retry_private: | |||
1679 | * woken by futex_unlock_pi(). | 1679 | * woken by futex_unlock_pi(). |
1680 | */ | 1680 | */ |
1681 | if (++task_count <= nr_wake && !requeue_pi) { | 1681 | if (++task_count <= nr_wake && !requeue_pi) { |
1682 | wake_futex(this); | 1682 | mark_wake_futex(&wake_q, this); |
1683 | continue; | 1683 | continue; |
1684 | } | 1684 | } |
1685 | 1685 | ||
@@ -1719,6 +1719,7 @@ retry_private: | |||
1719 | out_unlock: | 1719 | out_unlock: |
1720 | free_pi_state(pi_state); | 1720 | free_pi_state(pi_state); |
1721 | double_unlock_hb(hb1, hb2); | 1721 | double_unlock_hb(hb1, hb2); |
1722 | wake_up_q(&wake_q); | ||
1722 | hb_waiters_dec(hb2); | 1723 | hb_waiters_dec(hb2); |
1723 | 1724 | ||
1724 | /* | 1725 | /* |