diff options
author | Will Deacon <will.deacon@arm.com> | 2019-04-08 09:23:17 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2019-04-26 08:57:43 -0400 |
commit | 03110a5cb2161690ae5ac04994d47ed0cd6cef75 (patch) | |
tree | 9e228d9efb081b69dfb85f31b5ac314d75b39893 | |
parent | 6b4f4bc9cb22875f97023984a625386f0c7cc1c0 (diff) |
arm64: futex: Bound number of LDXR/STXR loops in FUTEX_WAKE_OP
Our futex implementation makes use of LDXR/STXR loops to perform atomic
updates to user memory from atomic context. This can lead to latency
problems if we end up spinning around the LL/SC sequence at the expense
of doing something useful.
Rework our futex atomic operations so that we return -EAGAIN if we fail
to update the futex word after 128 attempts. The core futex code will
reschedule if necessary and we'll try again later.
Cc: <stable@kernel.org>
Fixes: 6170a97460db ("arm64: Atomic operations")
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | arch/arm64/include/asm/futex.h | 55 |
1 files changed, 34 insertions, 21 deletions
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index e1d95f08f8e1..2d78ea6932b7 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 %w0, %w3, %2\n" \ | 37 | "2: stlxr %w0, %w3, %2\n" \ |
34 | " cbnz %w0, 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) |
@@ -57,23 +65,23 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr) | |||
57 | 65 | ||
58 | switch (op) { | 66 | switch (op) { |
59 | case FUTEX_OP_SET: | 67 | case FUTEX_OP_SET: |
60 | __futex_atomic_op("mov %w3, %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 %w3, %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 %w3, %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 %w3, %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 %w3, %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,20 +113,24 @@ 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 | ||