Commit c958f9200fb48d092b17d3784168e4a6c56bbddc
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull futex fixes from Ingo Molnar: "This contains two futex fixes: one fixes a race condition, the other clarifies shared/private futex comments" * 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: futex: Fix a race condition between REQUEUE_PI and task death futex: Mention key referencing differences between shared and private futexes
Showing 1 changed file Side-by-side Diff
kernel/futex.c
... | ... | @@ -143,9 +143,8 @@ |
143 | 143 | * |
144 | 144 | * Where (A) orders the waiters increment and the futex value read through |
145 | 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 | |
147 | - * get_futex_key_refs(), through either ihold or atomic_inc, depending on the | |
148 | - * futex type. | |
146 | + * to futex and the waiters read -- this is done by the barriers for both | |
147 | + * shared and private futexes in get_futex_key_refs(). | |
149 | 148 | * |
150 | 149 | * This yields the following case (where X:=waiters, Y:=futex): |
151 | 150 | * |
152 | 151 | |
... | ... | @@ -344,13 +343,20 @@ |
344 | 343 | futex_get_mm(key); /* implies MB (B) */ |
345 | 344 | break; |
346 | 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 | 351 | smp_mb(); /* explicit MB (B) */ |
348 | 352 | } |
349 | 353 | } |
350 | 354 | |
351 | 355 | /* |
352 | 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 | 361 | static void drop_futex_key_refs(union futex_key *key) |
356 | 362 | { |
357 | 363 | |
... | ... | @@ -641,8 +647,14 @@ |
641 | 647 | return pi_state; |
642 | 648 | } |
643 | 649 | |
650 | +/* | |
651 | + * Must be called with the hb lock held. | |
652 | + */ | |
644 | 653 | static void free_pi_state(struct futex_pi_state *pi_state) |
645 | 654 | { |
655 | + if (!pi_state) | |
656 | + return; | |
657 | + | |
646 | 658 | if (!atomic_dec_and_test(&pi_state->refcount)) |
647 | 659 | return; |
648 | 660 | |
... | ... | @@ -1521,15 +1533,6 @@ |
1521 | 1533 | } |
1522 | 1534 | |
1523 | 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 | 1536 | ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); |
1534 | 1537 | if (unlikely(ret != 0)) |
1535 | 1538 | goto out; |
... | ... | @@ -1619,6 +1622,8 @@ |
1619 | 1622 | case 0: |
1620 | 1623 | break; |
1621 | 1624 | case -EFAULT: |
1625 | + free_pi_state(pi_state); | |
1626 | + pi_state = NULL; | |
1622 | 1627 | double_unlock_hb(hb1, hb2); |
1623 | 1628 | hb_waiters_dec(hb2); |
1624 | 1629 | put_futex_key(&key2); |
... | ... | @@ -1634,6 +1639,8 @@ |
1634 | 1639 | * exit to complete. |
1635 | 1640 | * - The user space value changed. |
1636 | 1641 | */ |
1642 | + free_pi_state(pi_state); | |
1643 | + pi_state = NULL; | |
1637 | 1644 | double_unlock_hb(hb1, hb2); |
1638 | 1645 | hb_waiters_dec(hb2); |
1639 | 1646 | put_futex_key(&key2); |
... | ... | @@ -1710,6 +1717,7 @@ |
1710 | 1717 | } |
1711 | 1718 | |
1712 | 1719 | out_unlock: |
1720 | + free_pi_state(pi_state); | |
1713 | 1721 | double_unlock_hb(hb1, hb2); |
1714 | 1722 | hb_waiters_dec(hb2); |
1715 | 1723 | |
... | ... | @@ -1727,8 +1735,6 @@ |
1727 | 1735 | out_put_key1: |
1728 | 1736 | put_futex_key(&key1); |
1729 | 1737 | out: |
1730 | - if (pi_state != NULL) | |
1731 | - free_pi_state(pi_state); | |
1732 | 1738 | return ret ? ret : task_count; |
1733 | 1739 | } |
1734 | 1740 |