diff options
| author | Will Deacon <will.deacon@arm.com> | 2019-05-01 10:34:17 -0400 |
|---|---|---|
| committer | Will Deacon <will.deacon@arm.com> | 2019-05-01 10:34:17 -0400 |
| commit | 9431ac2bf6b742d87cdac051adc1976308070110 (patch) | |
| tree | 653c740b32bd411c2b79f81ecd6841f46814c87b | |
| parent | 61cf61d81e326163ce1557ceccfca76e11d0e57c (diff) | |
| parent | 427503519739e779c0db8afe876c1b33f3ac60ae (diff) | |
Merge branch 'for-next/futex' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux into for-next/core
| -rw-r--r-- | Documentation/robust-futexes.txt | 3 | ||||
| -rw-r--r-- | arch/arm64/include/asm/futex.h | 63 | ||||
| -rw-r--r-- | include/asm-generic/futex.h | 8 | ||||
| -rw-r--r-- | kernel/futex.c | 188 |
4 files changed, 163 insertions, 99 deletions
diff --git a/Documentation/robust-futexes.txt b/Documentation/robust-futexes.txt index 6c42c75103eb..6361fb01c9c1 100644 --- a/Documentation/robust-futexes.txt +++ b/Documentation/robust-futexes.txt | |||
| @@ -218,5 +218,4 @@ All other architectures should build just fine too - but they won't have | |||
| 218 | the new syscalls yet. | 218 | the new syscalls yet. |
| 219 | 219 | ||
| 220 | Architectures need to implement the new futex_atomic_cmpxchg_inatomic() | 220 | Architectures need to implement the new futex_atomic_cmpxchg_inatomic() |
| 221 | inline function before writing up the syscalls (that function returns | 221 | inline function before writing up the syscalls. |
| 222 | -ENOSYS right now). | ||
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index cccb83ad7fa8..bdb3c05070a2 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h | |||
| @@ -23,26 +23,34 @@ | |||
| 23 | 23 | ||
| 24 | #include <asm/errno.h> | 24 | #include <asm/errno.h> |
| 25 | 25 | ||
| 26 | #define FUTEX_MAX_LOOPS 128 /* What's the largest number you can think of? */ | ||
| 27 | |||
| 26 | #define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \ | 28 | #define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \ |
| 27 | do { \ | 29 | do { \ |
| 30 | unsigned int loops = FUTEX_MAX_LOOPS; \ | ||
| 31 | \ | ||
| 28 | uaccess_enable(); \ | 32 | uaccess_enable(); \ |
| 29 | asm volatile( \ | 33 | asm volatile( \ |
| 30 | " prfm pstl1strm, %2\n" \ | 34 | " prfm pstl1strm, %2\n" \ |
| 31 | "1: ldxr %w1, %2\n" \ | 35 | "1: ldxr %w1, %2\n" \ |
| 32 | insn "\n" \ | 36 | insn "\n" \ |
| 33 | "2: stlxr %w3, %w0, %2\n" \ | 37 | "2: stlxr %w0, %w3, %2\n" \ |
| 34 | " cbnz %w3, 1b\n" \ | 38 | " cbz %w0, 3f\n" \ |
| 35 | " dmb ish\n" \ | 39 | " sub %w4, %w4, %w0\n" \ |
| 40 | " cbnz %w4, 1b\n" \ | ||
| 41 | " mov %w0, %w7\n" \ | ||
| 36 | "3:\n" \ | 42 | "3:\n" \ |
| 43 | " dmb ish\n" \ | ||
| 37 | " .pushsection .fixup,\"ax\"\n" \ | 44 | " .pushsection .fixup,\"ax\"\n" \ |
| 38 | " .align 2\n" \ | 45 | " .align 2\n" \ |
| 39 | "4: mov %w0, %w5\n" \ | 46 | "4: mov %w0, %w6\n" \ |
| 40 | " b 3b\n" \ | 47 | " b 3b\n" \ |
| 41 | " .popsection\n" \ | 48 | " .popsection\n" \ |
| 42 | _ASM_EXTABLE(1b, 4b) \ | 49 | _ASM_EXTABLE(1b, 4b) \ |
| 43 | _ASM_EXTABLE(2b, 4b) \ | 50 | _ASM_EXTABLE(2b, 4b) \ |
| 44 | : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \ | 51 | : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp), \ |
| 45 | : "r" (oparg), "Ir" (-EFAULT) \ | 52 | "+r" (loops) \ |
| 53 | : "r" (oparg), "Ir" (-EFAULT), "Ir" (-EAGAIN) \ | ||
| 46 | : "memory"); \ | 54 | : "memory"); \ |
| 47 | uaccess_disable(); \ | 55 | uaccess_disable(); \ |
| 48 | } while (0) | 56 | } while (0) |
| @@ -50,30 +58,30 @@ do { \ | |||
| 50 | static inline int | 58 | static inline int |
| 51 | arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr) | 59 | arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr) |
| 52 | { | 60 | { |
| 53 | int oldval = 0, ret, tmp; | 61 | int oldval, ret, tmp; |
| 54 | u32 __user *uaddr = __uaccess_mask_ptr(_uaddr); | 62 | u32 __user *uaddr = __uaccess_mask_ptr(_uaddr); |
| 55 | 63 | ||
| 56 | pagefault_disable(); | 64 | pagefault_disable(); |
| 57 | 65 | ||
| 58 | switch (op) { | 66 | switch (op) { |
| 59 | case FUTEX_OP_SET: | 67 | case FUTEX_OP_SET: |
| 60 | __futex_atomic_op("mov %w0, %w4", | 68 | __futex_atomic_op("mov %w3, %w5", |
| 61 | ret, oldval, uaddr, tmp, oparg); | 69 | ret, oldval, uaddr, tmp, oparg); |
| 62 | break; | 70 | break; |
| 63 | case FUTEX_OP_ADD: | 71 | case FUTEX_OP_ADD: |
| 64 | __futex_atomic_op("add %w0, %w1, %w4", | 72 | __futex_atomic_op("add %w3, %w1, %w5", |
| 65 | ret, oldval, uaddr, tmp, oparg); | 73 | ret, oldval, uaddr, tmp, oparg); |
| 66 | break; | 74 | break; |
| 67 | case FUTEX_OP_OR: | 75 | case FUTEX_OP_OR: |
| 68 | __futex_atomic_op("orr %w0, %w1, %w4", | 76 | __futex_atomic_op("orr %w3, %w1, %w5", |
| 69 | ret, oldval, uaddr, tmp, oparg); | 77 | ret, oldval, uaddr, tmp, oparg); |
| 70 | break; | 78 | break; |
| 71 | case FUTEX_OP_ANDN: | 79 | case FUTEX_OP_ANDN: |
| 72 | __futex_atomic_op("and %w0, %w1, %w4", | 80 | __futex_atomic_op("and %w3, %w1, %w5", |
| 73 | ret, oldval, uaddr, tmp, ~oparg); | 81 | ret, oldval, uaddr, tmp, ~oparg); |
| 74 | break; | 82 | break; |
| 75 | case FUTEX_OP_XOR: | 83 | case FUTEX_OP_XOR: |
| 76 | __futex_atomic_op("eor %w0, %w1, %w4", | 84 | __futex_atomic_op("eor %w3, %w1, %w5", |
| 77 | ret, oldval, uaddr, tmp, oparg); | 85 | ret, oldval, uaddr, tmp, oparg); |
| 78 | break; | 86 | break; |
| 79 | default: | 87 | default: |
| @@ -93,6 +101,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr, | |||
| 93 | u32 oldval, u32 newval) | 101 | u32 oldval, u32 newval) |
| 94 | { | 102 | { |
| 95 | int ret = 0; | 103 | int ret = 0; |
| 104 | unsigned int loops = FUTEX_MAX_LOOPS; | ||
| 96 | u32 val, tmp; | 105 | u32 val, tmp; |
| 97 | u32 __user *uaddr; | 106 | u32 __user *uaddr; |
| 98 | 107 | ||
| @@ -104,24 +113,30 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr, | |||
| 104 | asm volatile("// futex_atomic_cmpxchg_inatomic\n" | 113 | asm volatile("// futex_atomic_cmpxchg_inatomic\n" |
| 105 | " prfm pstl1strm, %2\n" | 114 | " prfm pstl1strm, %2\n" |
| 106 | "1: ldxr %w1, %2\n" | 115 | "1: ldxr %w1, %2\n" |
| 107 | " sub %w3, %w1, %w4\n" | 116 | " sub %w3, %w1, %w5\n" |
| 108 | " cbnz %w3, 3f\n" | 117 | " cbnz %w3, 4f\n" |
| 109 | "2: stlxr %w3, %w5, %2\n" | 118 | "2: stlxr %w3, %w6, %2\n" |
| 110 | " cbnz %w3, 1b\n" | 119 | " cbz %w3, 3f\n" |
| 111 | " dmb ish\n" | 120 | " sub %w4, %w4, %w3\n" |
| 121 | " cbnz %w4, 1b\n" | ||
| 122 | " mov %w0, %w8\n" | ||
| 112 | "3:\n" | 123 | "3:\n" |
| 124 | " dmb ish\n" | ||
| 125 | "4:\n" | ||
| 113 | " .pushsection .fixup,\"ax\"\n" | 126 | " .pushsection .fixup,\"ax\"\n" |
| 114 | "4: mov %w0, %w6\n" | 127 | "5: mov %w0, %w7\n" |
| 115 | " b 3b\n" | 128 | " b 4b\n" |
| 116 | " .popsection\n" | 129 | " .popsection\n" |
| 117 | _ASM_EXTABLE(1b, 4b) | 130 | _ASM_EXTABLE(1b, 5b) |
| 118 | _ASM_EXTABLE(2b, 4b) | 131 | _ASM_EXTABLE(2b, 5b) |
| 119 | : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp) | 132 | : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp), "+r" (loops) |
| 120 | : "r" (oldval), "r" (newval), "Ir" (-EFAULT) | 133 | : "r" (oldval), "r" (newval), "Ir" (-EFAULT), "Ir" (-EAGAIN) |
| 121 | : "memory"); | 134 | : "memory"); |
| 122 | uaccess_disable(); | 135 | uaccess_disable(); |
| 123 | 136 | ||
| 124 | *uval = val; | 137 | if (!ret) |
| 138 | *uval = val; | ||
| 139 | |||
| 125 | return ret; | 140 | return ret; |
| 126 | } | 141 | } |
| 127 | 142 | ||
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h index fcb61b4659b3..8666fe7f35d7 100644 --- a/include/asm-generic/futex.h +++ b/include/asm-generic/futex.h | |||
| @@ -23,7 +23,9 @@ | |||
| 23 | * | 23 | * |
| 24 | * Return: | 24 | * Return: |
| 25 | * 0 - On success | 25 | * 0 - On success |
| 26 | * <0 - On error | 26 | * -EFAULT - User access resulted in a page fault |
| 27 | * -EAGAIN - Atomic operation was unable to complete due to contention | ||
| 28 | * -ENOSYS - Operation not supported | ||
| 27 | */ | 29 | */ |
| 28 | static inline int | 30 | static inline int |
| 29 | arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) | 31 | arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) |
| @@ -85,7 +87,9 @@ out_pagefault_enable: | |||
| 85 | * | 87 | * |
| 86 | * Return: | 88 | * Return: |
| 87 | * 0 - On success | 89 | * 0 - On success |
| 88 | * <0 - On error | 90 | * -EFAULT - User access resulted in a page fault |
| 91 | * -EAGAIN - Atomic operation was unable to complete due to contention | ||
| 92 | * -ENOSYS - Function not implemented (only if !HAVE_FUTEX_CMPXCHG) | ||
| 89 | */ | 93 | */ |
| 90 | static inline int | 94 | static inline int |
| 91 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | 95 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, |
diff --git a/kernel/futex.c b/kernel/futex.c index 9e40cf7be606..6262f1534ac9 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
| @@ -1311,13 +1311,15 @@ static int lookup_pi_state(u32 __user *uaddr, u32 uval, | |||
| 1311 | 1311 | ||
| 1312 | static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval) | 1312 | static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval) |
| 1313 | { | 1313 | { |
| 1314 | int err; | ||
| 1314 | u32 uninitialized_var(curval); | 1315 | u32 uninitialized_var(curval); |
| 1315 | 1316 | ||
| 1316 | if (unlikely(should_fail_futex(true))) | 1317 | if (unlikely(should_fail_futex(true))) |
| 1317 | return -EFAULT; | 1318 | return -EFAULT; |
| 1318 | 1319 | ||
| 1319 | if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))) | 1320 | err = cmpxchg_futex_value_locked(&curval, uaddr, uval, newval); |
| 1320 | return -EFAULT; | 1321 | if (unlikely(err)) |
| 1322 | return err; | ||
| 1321 | 1323 | ||
| 1322 | /* If user space value changed, let the caller retry */ | 1324 | /* If user space value changed, let the caller retry */ |
| 1323 | return curval != uval ? -EAGAIN : 0; | 1325 | return curval != uval ? -EAGAIN : 0; |
| @@ -1502,10 +1504,8 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_pi_state *pi_ | |||
| 1502 | if (unlikely(should_fail_futex(true))) | 1504 | if (unlikely(should_fail_futex(true))) |
| 1503 | ret = -EFAULT; | 1505 | ret = -EFAULT; |
| 1504 | 1506 | ||
| 1505 | if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) { | 1507 | ret = cmpxchg_futex_value_locked(&curval, uaddr, uval, newval); |
| 1506 | ret = -EFAULT; | 1508 | if (!ret && (curval != uval)) { |
| 1507 | |||
| 1508 | } else if (curval != uval) { | ||
| 1509 | /* | 1509 | /* |
| 1510 | * If a unconditional UNLOCK_PI operation (user space did not | 1510 | * If a unconditional UNLOCK_PI operation (user space did not |
| 1511 | * try the TID->0 transition) raced with a waiter setting the | 1511 | * try the TID->0 transition) raced with a waiter setting the |
| @@ -1700,32 +1700,32 @@ retry_private: | |||
| 1700 | double_lock_hb(hb1, hb2); | 1700 | double_lock_hb(hb1, hb2); |
| 1701 | op_ret = futex_atomic_op_inuser(op, uaddr2); | 1701 | op_ret = futex_atomic_op_inuser(op, uaddr2); |
| 1702 | if (unlikely(op_ret < 0)) { | 1702 | if (unlikely(op_ret < 0)) { |
| 1703 | |||
| 1704 | double_unlock_hb(hb1, hb2); | 1703 | double_unlock_hb(hb1, hb2); |
| 1705 | 1704 | ||
| 1706 | #ifndef CONFIG_MMU | 1705 | if (!IS_ENABLED(CONFIG_MMU) || |
| 1707 | /* | 1706 | unlikely(op_ret != -EFAULT && op_ret != -EAGAIN)) { |
| 1708 | * we don't get EFAULT from MMU faults if we don't have an MMU, | 1707 | /* |
| 1709 | * but we might get them from range checking | 1708 | * we don't get EFAULT from MMU faults if we don't have |
| 1710 | */ | 1709 | * an MMU, but we might get them from range checking |
| 1711 | ret = op_ret; | 1710 | */ |
| 1712 | goto out_put_keys; | ||
| 1713 | #endif | ||
| 1714 | |||
| 1715 | if (unlikely(op_ret != -EFAULT)) { | ||
| 1716 | ret = op_ret; | 1711 | ret = op_ret; |
| 1717 | goto out_put_keys; | 1712 | goto out_put_keys; |
| 1718 | } | 1713 | } |
| 1719 | 1714 | ||
| 1720 | ret = fault_in_user_writeable(uaddr2); | 1715 | if (op_ret == -EFAULT) { |
| 1721 | if (ret) | 1716 | ret = fault_in_user_writeable(uaddr2); |
| 1722 | goto out_put_keys; | 1717 | if (ret) |
| 1718 | goto out_put_keys; | ||
| 1719 | } | ||
| 1723 | 1720 | ||
| 1724 | if (!(flags & FLAGS_SHARED)) | 1721 | if (!(flags & FLAGS_SHARED)) { |
| 1722 | cond_resched(); | ||
| 1725 | goto retry_private; | 1723 | goto retry_private; |
| 1724 | } | ||
| 1726 | 1725 | ||
| 1727 | put_futex_key(&key2); | 1726 | put_futex_key(&key2); |
| 1728 | put_futex_key(&key1); | 1727 | put_futex_key(&key1); |
| 1728 | cond_resched(); | ||
| 1729 | goto retry; | 1729 | goto retry; |
| 1730 | } | 1730 | } |
| 1731 | 1731 | ||
| @@ -2350,7 +2350,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, | |||
| 2350 | u32 uval, uninitialized_var(curval), newval; | 2350 | u32 uval, uninitialized_var(curval), newval; |
| 2351 | struct task_struct *oldowner, *newowner; | 2351 | struct task_struct *oldowner, *newowner; |
| 2352 | u32 newtid; | 2352 | u32 newtid; |
| 2353 | int ret; | 2353 | int ret, err = 0; |
| 2354 | 2354 | ||
| 2355 | lockdep_assert_held(q->lock_ptr); | 2355 | lockdep_assert_held(q->lock_ptr); |
| 2356 | 2356 | ||
| @@ -2421,14 +2421,17 @@ retry: | |||
| 2421 | if (!pi_state->owner) | 2421 | if (!pi_state->owner) |
| 2422 | newtid |= FUTEX_OWNER_DIED; | 2422 | newtid |= FUTEX_OWNER_DIED; |
| 2423 | 2423 | ||
| 2424 | if (get_futex_value_locked(&uval, uaddr)) | 2424 | err = get_futex_value_locked(&uval, uaddr); |
| 2425 | goto handle_fault; | 2425 | if (err) |
| 2426 | goto handle_err; | ||
| 2426 | 2427 | ||
| 2427 | for (;;) { | 2428 | for (;;) { |
| 2428 | newval = (uval & FUTEX_OWNER_DIED) | newtid; | 2429 | newval = (uval & FUTEX_OWNER_DIED) | newtid; |
| 2429 | 2430 | ||
| 2430 | if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) | 2431 | err = cmpxchg_futex_value_locked(&curval, uaddr, uval, newval); |
| 2431 | goto handle_fault; | 2432 | if (err) |
| 2433 | goto handle_err; | ||
| 2434 | |||
| 2432 | if (curval == uval) | 2435 | if (curval == uval) |
| 2433 | break; | 2436 | break; |
| 2434 | uval = curval; | 2437 | uval = curval; |
| @@ -2456,23 +2459,37 @@ retry: | |||
| 2456 | return 0; | 2459 | return 0; |
| 2457 | 2460 | ||
| 2458 | /* | 2461 | /* |
| 2459 | * To handle the page fault we need to drop the locks here. That gives | 2462 | * In order to reschedule or handle a page fault, we need to drop the |
| 2460 | * the other task (either the highest priority waiter itself or the | 2463 | * locks here. In the case of a fault, this gives the other task |
| 2461 | * task which stole the rtmutex) the chance to try the fixup of the | 2464 | * (either the highest priority waiter itself or the task which stole |
| 2462 | * pi_state. So once we are back from handling the fault we need to | 2465 | * the rtmutex) the chance to try the fixup of the pi_state. So once we |
| 2463 | * check the pi_state after reacquiring the locks and before trying to | 2466 | * are back from handling the fault we need to check the pi_state after |
| 2464 | * do another fixup. When the fixup has been done already we simply | 2467 | * reacquiring the locks and before trying to do another fixup. When |
| 2465 | * return. | 2468 | * the fixup has been done already we simply return. |
| 2466 | * | 2469 | * |
| 2467 | * Note: we hold both hb->lock and pi_mutex->wait_lock. We can safely | 2470 | * Note: we hold both hb->lock and pi_mutex->wait_lock. We can safely |
| 2468 | * drop hb->lock since the caller owns the hb -> futex_q relation. | 2471 | * drop hb->lock since the caller owns the hb -> futex_q relation. |
| 2469 | * Dropping the pi_mutex->wait_lock requires the state revalidate. | 2472 | * Dropping the pi_mutex->wait_lock requires the state revalidate. |
| 2470 | */ | 2473 | */ |
| 2471 | handle_fault: | 2474 | handle_err: |
| 2472 | raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock); | 2475 | raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock); |
| 2473 | spin_unlock(q->lock_ptr); | 2476 | spin_unlock(q->lock_ptr); |
| 2474 | 2477 | ||
| 2475 | ret = fault_in_user_writeable(uaddr); | 2478 | switch (err) { |
| 2479 | case -EFAULT: | ||
| 2480 | ret = fault_in_user_writeable(uaddr); | ||
| 2481 | break; | ||
| 2482 | |||
| 2483 | case -EAGAIN: | ||
| 2484 | cond_resched(); | ||
| 2485 | ret = 0; | ||
| 2486 | break; | ||
| 2487 | |||
| 2488 | default: | ||
| 2489 | WARN_ON_ONCE(1); | ||
| 2490 | ret = err; | ||
| 2491 | break; | ||
| 2492 | } | ||
| 2476 | 2493 | ||
| 2477 | spin_lock(q->lock_ptr); | 2494 | spin_lock(q->lock_ptr); |
| 2478 | raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock); | 2495 | raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock); |
| @@ -3041,10 +3058,8 @@ retry: | |||
| 3041 | * A unconditional UNLOCK_PI op raced against a waiter | 3058 | * A unconditional UNLOCK_PI op raced against a waiter |
| 3042 | * setting the FUTEX_WAITERS bit. Try again. | 3059 | * setting the FUTEX_WAITERS bit. Try again. |
| 3043 | */ | 3060 | */ |
| 3044 | if (ret == -EAGAIN) { | 3061 | if (ret == -EAGAIN) |
| 3045 | put_futex_key(&key); | 3062 | goto pi_retry; |
| 3046 | goto retry; | ||
| 3047 | } | ||
| 3048 | /* | 3063 | /* |
| 3049 | * wake_futex_pi has detected invalid state. Tell user | 3064 | * wake_futex_pi has detected invalid state. Tell user |
| 3050 | * space. | 3065 | * space. |
| @@ -3059,9 +3074,19 @@ retry: | |||
| 3059 | * preserve the WAITERS bit not the OWNER_DIED one. We are the | 3074 | * preserve the WAITERS bit not the OWNER_DIED one. We are the |
| 3060 | * owner. | 3075 | * owner. |
| 3061 | */ | 3076 | */ |
| 3062 | if (cmpxchg_futex_value_locked(&curval, uaddr, uval, 0)) { | 3077 | if ((ret = cmpxchg_futex_value_locked(&curval, uaddr, uval, 0))) { |
| 3063 | spin_unlock(&hb->lock); | 3078 | spin_unlock(&hb->lock); |
| 3064 | goto pi_faulted; | 3079 | switch (ret) { |
| 3080 | case -EFAULT: | ||
| 3081 | goto pi_faulted; | ||
| 3082 | |||
| 3083 | case -EAGAIN: | ||
| 3084 | goto pi_retry; | ||
| 3085 | |||
| 3086 | default: | ||
| 3087 | WARN_ON_ONCE(1); | ||
| 3088 | goto out_putkey; | ||
| 3089 | } | ||
| 3065 | } | 3090 | } |
| 3066 | 3091 | ||
| 3067 | /* | 3092 | /* |
| @@ -3075,6 +3100,11 @@ out_putkey: | |||
| 3075 | put_futex_key(&key); | 3100 | put_futex_key(&key); |
| 3076 | return ret; | 3101 | return ret; |
| 3077 | 3102 | ||
| 3103 | pi_retry: | ||
| 3104 | put_futex_key(&key); | ||
| 3105 | cond_resched(); | ||
| 3106 | goto retry; | ||
| 3107 | |||
| 3078 | pi_faulted: | 3108 | pi_faulted: |
| 3079 | put_futex_key(&key); | 3109 | put_futex_key(&key); |
| 3080 | 3110 | ||
| @@ -3435,6 +3465,7 @@ err_unlock: | |||
| 3435 | static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi) | 3465 | static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi) |
| 3436 | { | 3466 | { |
| 3437 | u32 uval, uninitialized_var(nval), mval; | 3467 | u32 uval, uninitialized_var(nval), mval; |
| 3468 | int err; | ||
| 3438 | 3469 | ||
| 3439 | /* Futex address must be 32bit aligned */ | 3470 | /* Futex address must be 32bit aligned */ |
| 3440 | if ((((unsigned long)uaddr) % sizeof(*uaddr)) != 0) | 3471 | if ((((unsigned long)uaddr) % sizeof(*uaddr)) != 0) |
| @@ -3444,42 +3475,57 @@ retry: | |||
| 3444 | if (get_user(uval, uaddr)) | 3475 | if (get_user(uval, uaddr)) |
| 3445 | return -1; | 3476 | return -1; |
| 3446 | 3477 | ||
| 3447 | if ((uval & FUTEX_TID_MASK) == task_pid_vnr(curr)) { | 3478 | if ((uval & FUTEX_TID_MASK) != task_pid_vnr(curr)) |
| 3448 | /* | 3479 | return 0; |
| 3449 | * Ok, this dying thread is truly holding a futex | 3480 | |
| 3450 | * of interest. Set the OWNER_DIED bit atomically | 3481 | /* |
| 3451 | * via cmpxchg, and if the value had FUTEX_WAITERS | 3482 | * Ok, this dying thread is truly holding a futex |
| 3452 | * set, wake up a waiter (if any). (We have to do a | 3483 | * of interest. Set the OWNER_DIED bit atomically |
| 3453 | * futex_wake() even if OWNER_DIED is already set - | 3484 | * via cmpxchg, and if the value had FUTEX_WAITERS |
| 3454 | * to handle the rare but possible case of recursive | 3485 | * set, wake up a waiter (if any). (We have to do a |
| 3455 | * thread-death.) The rest of the cleanup is done in | 3486 | * futex_wake() even if OWNER_DIED is already set - |
| 3456 | * userspace. | 3487 | * to handle the rare but possible case of recursive |
| 3457 | */ | 3488 | * thread-death.) The rest of the cleanup is done in |
| 3458 | mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED; | 3489 | * userspace. |
| 3459 | /* | 3490 | */ |
| 3460 | * We are not holding a lock here, but we want to have | 3491 | mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED; |
| 3461 | * the pagefault_disable/enable() protection because | 3492 | |
| 3462 | * we want to handle the fault gracefully. If the | 3493 | /* |
| 3463 | * access fails we try to fault in the futex with R/W | 3494 | * We are not holding a lock here, but we want to have |
| 3464 | * verification via get_user_pages. get_user() above | 3495 | * the pagefault_disable/enable() protection because |
| 3465 | * does not guarantee R/W access. If that fails we | 3496 | * we want to handle the fault gracefully. If the |
| 3466 | * give up and leave the futex locked. | 3497 | * access fails we try to fault in the futex with R/W |
| 3467 | */ | 3498 | * verification via get_user_pages. get_user() above |
| 3468 | if (cmpxchg_futex_value_locked(&nval, uaddr, uval, mval)) { | 3499 | * does not guarantee R/W access. If that fails we |
| 3500 | * give up and leave the futex locked. | ||
| 3501 | */ | ||
| 3502 | if ((err = cmpxchg_futex_value_locked(&nval, uaddr, uval, mval))) { | ||
| 3503 | switch (err) { | ||
| 3504 | case -EFAULT: | ||
| 3469 | if (fault_in_user_writeable(uaddr)) | 3505 | if (fault_in_user_writeable(uaddr)) |
| 3470 | return -1; | 3506 | return -1; |
| 3471 | goto retry; | 3507 | goto retry; |
| 3472 | } | 3508 | |
| 3473 | if (nval != uval) | 3509 | case -EAGAIN: |
| 3510 | cond_resched(); | ||
| 3474 | goto retry; | 3511 | goto retry; |
| 3475 | 3512 | ||
| 3476 | /* | 3513 | default: |
| 3477 | * Wake robust non-PI futexes here. The wakeup of | 3514 | WARN_ON_ONCE(1); |
| 3478 | * PI futexes happens in exit_pi_state(): | 3515 | return err; |
| 3479 | */ | 3516 | } |
| 3480 | if (!pi && (uval & FUTEX_WAITERS)) | ||
| 3481 | futex_wake(uaddr, 1, 1, FUTEX_BITSET_MATCH_ANY); | ||
| 3482 | } | 3517 | } |
| 3518 | |||
| 3519 | if (nval != uval) | ||
| 3520 | goto retry; | ||
| 3521 | |||
| 3522 | /* | ||
| 3523 | * Wake robust non-PI futexes here. The wakeup of | ||
| 3524 | * PI futexes happens in exit_pi_state(): | ||
| 3525 | */ | ||
| 3526 | if (!pi && (uval & FUTEX_WAITERS)) | ||
| 3527 | futex_wake(uaddr, 1, 1, FUTEX_BITSET_MATCH_ANY); | ||
| 3528 | |||
| 3483 | return 0; | 3529 | return 0; |
| 3484 | } | 3530 | } |
| 3485 | 3531 | ||
