diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 36 |
1 files changed, 21 insertions, 15 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index f3a3a071283c..63678b573d61 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -143,9 +143,8 @@ | |||
143 | * | 143 | * |
144 | * Where (A) orders the waiters increment and the futex value read through | 144 | * Where (A) orders the waiters increment and the futex value read through |
145 | * atomic operations (see hb_waiters_inc) and where (B) orders the write | 145 | * atomic operations (see hb_waiters_inc) and where (B) orders the write |
146 | * to futex and the waiters read -- this is done by the barriers in | 146 | * to futex and the waiters read -- this is done by the barriers for both |
147 | * get_futex_key_refs(), through either ihold or atomic_inc, depending on the | 147 | * shared and private futexes in get_futex_key_refs(). |
148 | * futex type. | ||
149 | * | 148 | * |
150 | * This yields the following case (where X:=waiters, Y:=futex): | 149 | * This yields the following case (where X:=waiters, Y:=futex): |
151 | * | 150 | * |
@@ -344,13 +343,20 @@ static void get_futex_key_refs(union futex_key *key) | |||
344 | futex_get_mm(key); /* implies MB (B) */ | 343 | futex_get_mm(key); /* implies MB (B) */ |
345 | break; | 344 | break; |
346 | default: | 345 | default: |
346 | /* | ||
347 | * Private futexes do not hold reference on an inode or | ||
348 | * mm, therefore the only purpose of calling get_futex_key_refs | ||
349 | * is because we need the barrier for the lockless waiter check. | ||
350 | */ | ||
347 | smp_mb(); /* explicit MB (B) */ | 351 | smp_mb(); /* explicit MB (B) */ |
348 | } | 352 | } |
349 | } | 353 | } |
350 | 354 | ||
351 | /* | 355 | /* |
352 | * Drop a reference to the resource addressed by a key. | 356 | * Drop a reference to the resource addressed by a key. |
353 | * The hash bucket spinlock must not be held. | 357 | * The hash bucket spinlock must not be held. This is |
358 | * a no-op for private futexes, see comment in the get | ||
359 | * counterpart. | ||
354 | */ | 360 | */ |
355 | static void drop_futex_key_refs(union futex_key *key) | 361 | static void drop_futex_key_refs(union futex_key *key) |
356 | { | 362 | { |
@@ -641,8 +647,14 @@ static struct futex_pi_state * alloc_pi_state(void) | |||
641 | return pi_state; | 647 | return pi_state; |
642 | } | 648 | } |
643 | 649 | ||
650 | /* | ||
651 | * Must be called with the hb lock held. | ||
652 | */ | ||
644 | static void free_pi_state(struct futex_pi_state *pi_state) | 653 | static void free_pi_state(struct futex_pi_state *pi_state) |
645 | { | 654 | { |
655 | if (!pi_state) | ||
656 | return; | ||
657 | |||
646 | if (!atomic_dec_and_test(&pi_state->refcount)) | 658 | if (!atomic_dec_and_test(&pi_state->refcount)) |
647 | return; | 659 | return; |
648 | 660 | ||
@@ -1521,15 +1533,6 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, | |||
1521 | } | 1533 | } |
1522 | 1534 | ||
1523 | retry: | 1535 | retry: |
1524 | if (pi_state != NULL) { | ||
1525 | /* | ||
1526 | * We will have to lookup the pi_state again, so free this one | ||
1527 | * to keep the accounting correct. | ||
1528 | */ | ||
1529 | free_pi_state(pi_state); | ||
1530 | pi_state = NULL; | ||
1531 | } | ||
1532 | |||
1533 | ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); | 1536 | ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); |
1534 | if (unlikely(ret != 0)) | 1537 | if (unlikely(ret != 0)) |
1535 | goto out; | 1538 | goto out; |
@@ -1619,6 +1622,8 @@ retry_private: | |||
1619 | case 0: | 1622 | case 0: |
1620 | break; | 1623 | break; |
1621 | case -EFAULT: | 1624 | case -EFAULT: |
1625 | free_pi_state(pi_state); | ||
1626 | pi_state = NULL; | ||
1622 | double_unlock_hb(hb1, hb2); | 1627 | double_unlock_hb(hb1, hb2); |
1623 | hb_waiters_dec(hb2); | 1628 | hb_waiters_dec(hb2); |
1624 | put_futex_key(&key2); | 1629 | put_futex_key(&key2); |
@@ -1634,6 +1639,8 @@ retry_private: | |||
1634 | * exit to complete. | 1639 | * exit to complete. |
1635 | * - The user space value changed. | 1640 | * - The user space value changed. |
1636 | */ | 1641 | */ |
1642 | free_pi_state(pi_state); | ||
1643 | pi_state = NULL; | ||
1637 | double_unlock_hb(hb1, hb2); | 1644 | double_unlock_hb(hb1, hb2); |
1638 | hb_waiters_dec(hb2); | 1645 | hb_waiters_dec(hb2); |
1639 | put_futex_key(&key2); | 1646 | put_futex_key(&key2); |
@@ -1710,6 +1717,7 @@ retry_private: | |||
1710 | } | 1717 | } |
1711 | 1718 | ||
1712 | out_unlock: | 1719 | out_unlock: |
1720 | free_pi_state(pi_state); | ||
1713 | double_unlock_hb(hb1, hb2); | 1721 | double_unlock_hb(hb1, hb2); |
1714 | hb_waiters_dec(hb2); | 1722 | hb_waiters_dec(hb2); |
1715 | 1723 | ||
@@ -1727,8 +1735,6 @@ out_put_keys: | |||
1727 | out_put_key1: | 1735 | out_put_key1: |
1728 | put_futex_key(&key1); | 1736 | put_futex_key(&key1); |
1729 | out: | 1737 | out: |
1730 | if (pi_state != NULL) | ||
1731 | free_pi_state(pi_state); | ||
1732 | return ret ? ret : task_count; | 1738 | return ret ? ret : task_count; |
1733 | } | 1739 | } |
1734 | 1740 | ||