summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2019-04-08 09:23:17 -0400
committerWill Deacon <will.deacon@arm.com>2019-04-26 08:57:43 -0400
commit03110a5cb2161690ae5ac04994d47ed0cd6cef75 (patch)
tree9e228d9efb081b69dfb85f31b5ac314d75b39893
parent6b4f4bc9cb22875f97023984a625386f0c7cc1c0 (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.h55
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) \
27do { \ 29do { \
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