]>
Commit | Line | Data |
---|---|---|
7eb50402 GKH |
1 | From 30d6e0a4190d37740e9447e4e4815f06992dd8c3 Mon Sep 17 00:00:00 2001 |
2 | From: Jiri Slaby <jslaby@suse.cz> | |
3 | Date: Thu, 24 Aug 2017 09:31:05 +0200 | |
4 | Subject: futex: Remove duplicated code and fix undefined behaviour | |
5 | ||
6 | From: Jiri Slaby <jslaby@suse.cz> | |
7 | ||
8 | commit 30d6e0a4190d37740e9447e4e4815f06992dd8c3 upstream. | |
9 | ||
10 | There is code duplicated over all architecture's headers for | |
11 | futex_atomic_op_inuser. Namely op decoding, access_ok check for uaddr, | |
12 | and comparison of the result. | |
13 | ||
14 | Remove this duplication and leave up to the arches only the needed | |
15 | assembly which is now in arch_futex_atomic_op_inuser. | |
16 | ||
17 | This effectively distributes the Will Deacon's arm64 fix for undefined | |
18 | behaviour reported by UBSAN to all architectures. The fix was done in | |
19 | commit 5f16a046f8e1 (arm64: futex: Fix undefined behaviour with | |
20 | FUTEX_OP_OPARG_SHIFT usage). Look there for an example dump. | |
21 | ||
22 | And as suggested by Thomas, check for negative oparg too, because it was | |
23 | also reported to cause undefined behaviour report. | |
24 | ||
25 | Note that s390 removed access_ok check in d12a29703 ("s390/uaccess: | |
26 | remove pointless access_ok() checks") as access_ok there returns true. | |
27 | We introduce it back to the helper for the sake of simplicity (it gets | |
28 | optimized away anyway). | |
29 | ||
30 | Signed-off-by: Jiri Slaby <jslaby@suse.cz> | |
31 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
32 | Acked-by: Russell King <rmk+kernel@armlinux.org.uk> | |
33 | Acked-by: Michael Ellerman <mpe@ellerman.id.au> (powerpc) | |
34 | Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com> [s390] | |
35 | Acked-by: Chris Metcalf <cmetcalf@mellanox.com> [for tile] | |
36 | Reviewed-by: Darren Hart (VMware) <dvhart@infradead.org> | |
37 | Reviewed-by: Will Deacon <will.deacon@arm.com> [core/arm64] | |
38 | Cc: linux-mips@linux-mips.org | |
39 | Cc: Rich Felker <dalias@libc.org> | |
40 | Cc: linux-ia64@vger.kernel.org | |
41 | Cc: linux-sh@vger.kernel.org | |
42 | Cc: peterz@infradead.org | |
43 | Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> | |
44 | Cc: Max Filippov <jcmvbkbc@gmail.com> | |
45 | Cc: Paul Mackerras <paulus@samba.org> | |
46 | Cc: sparclinux@vger.kernel.org | |
47 | Cc: Jonas Bonn <jonas@southpole.se> | |
48 | Cc: linux-s390@vger.kernel.org | |
49 | Cc: linux-arch@vger.kernel.org | |
50 | Cc: Yoshinori Sato <ysato@users.sourceforge.jp> | |
51 | Cc: linux-hexagon@vger.kernel.org | |
52 | Cc: Helge Deller <deller@gmx.de> | |
53 | Cc: "James E.J. Bottomley" <jejb@parisc-linux.org> | |
54 | Cc: Catalin Marinas <catalin.marinas@arm.com> | |
55 | Cc: Matt Turner <mattst88@gmail.com> | |
56 | Cc: linux-snps-arc@lists.infradead.org | |
57 | Cc: Fenghua Yu <fenghua.yu@intel.com> | |
58 | Cc: Arnd Bergmann <arnd@arndb.de> | |
59 | Cc: linux-xtensa@linux-xtensa.org | |
60 | Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> | |
61 | Cc: openrisc@lists.librecores.org | |
62 | Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru> | |
63 | Cc: Stafford Horne <shorne@gmail.com> | |
64 | Cc: linux-arm-kernel@lists.infradead.org | |
65 | Cc: Richard Henderson <rth@twiddle.net> | |
66 | Cc: Chris Zankel <chris@zankel.net> | |
67 | Cc: Michal Simek <monstr@monstr.eu> | |
68 | Cc: Tony Luck <tony.luck@intel.com> | |
69 | Cc: linux-parisc@vger.kernel.org | |
70 | Cc: Vineet Gupta <vgupta@synopsys.com> | |
71 | Cc: Ralf Baechle <ralf@linux-mips.org> | |
72 | Cc: Richard Kuo <rkuo@codeaurora.org> | |
73 | Cc: linux-alpha@vger.kernel.org | |
74 | Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> | |
75 | Cc: linuxppc-dev@lists.ozlabs.org | |
76 | Cc: "David S. Miller" <davem@davemloft.net> | |
77 | Link: http://lkml.kernel.org/r/20170824073105.3901-1-jslaby@suse.cz | |
78 | Cc: Ben Hutchings <ben.hutchings@codethink.co.uk> | |
79 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
80 | ||
81 | --- | |
82 | arch/alpha/include/asm/futex.h | 26 +++--------------- | |
83 | arch/arc/include/asm/futex.h | 40 +++------------------------- | |
84 | arch/arm/include/asm/futex.h | 26 ++---------------- | |
85 | arch/arm64/include/asm/futex.h | 26 ++---------------- | |
86 | arch/frv/include/asm/futex.h | 3 +- | |
87 | arch/frv/kernel/futex.c | 27 ++----------------- | |
88 | arch/hexagon/include/asm/futex.h | 38 ++------------------------- | |
89 | arch/ia64/include/asm/futex.h | 25 ++---------------- | |
90 | arch/microblaze/include/asm/futex.h | 38 ++------------------------- | |
91 | arch/mips/include/asm/futex.h | 25 ++---------------- | |
92 | arch/parisc/include/asm/futex.h | 25 ++---------------- | |
93 | arch/powerpc/include/asm/futex.h | 26 +++--------------- | |
94 | arch/s390/include/asm/futex.h | 23 +++------------- | |
95 | arch/sh/include/asm/futex.h | 26 ++---------------- | |
96 | arch/sparc/include/asm/futex_64.h | 26 +++--------------- | |
97 | arch/tile/include/asm/futex.h | 40 +++------------------------- | |
98 | arch/x86/include/asm/futex.h | 40 +++------------------------- | |
99 | arch/xtensa/include/asm/futex.h | 27 +++---------------- | |
100 | include/asm-generic/futex.h | 50 ++++++------------------------------ | |
101 | kernel/futex.c | 39 ++++++++++++++++++++++++++++ | |
102 | 20 files changed, 126 insertions(+), 470 deletions(-) | |
103 | ||
104 | --- a/arch/alpha/include/asm/futex.h | |
105 | +++ b/arch/alpha/include/asm/futex.h | |
106 | @@ -29,18 +29,10 @@ | |
107 | : "r" (uaddr), "r"(oparg) \ | |
108 | : "memory") | |
109 | ||
110 | -static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) | |
111 | +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, | |
112 | + u32 __user *uaddr) | |
113 | { | |
114 | - int op = (encoded_op >> 28) & 7; | |
115 | - int cmp = (encoded_op >> 24) & 15; | |
116 | - int oparg = (encoded_op << 8) >> 20; | |
117 | - int cmparg = (encoded_op << 20) >> 20; | |
118 | int oldval = 0, ret; | |
119 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
120 | - oparg = 1 << oparg; | |
121 | - | |
122 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
123 | - return -EFAULT; | |
124 | ||
125 | pagefault_disable(); | |
126 | ||
127 | @@ -66,17 +58,9 @@ static inline int futex_atomic_op_inuser | |
128 | ||
129 | pagefault_enable(); | |
130 | ||
131 | - if (!ret) { | |
132 | - switch (cmp) { | |
133 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
134 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
135 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
136 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
137 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
138 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
139 | - default: ret = -ENOSYS; | |
140 | - } | |
141 | - } | |
142 | + if (!ret) | |
143 | + *oval = oldval; | |
144 | + | |
145 | return ret; | |
146 | } | |
147 | ||
148 | --- a/arch/arc/include/asm/futex.h | |
149 | +++ b/arch/arc/include/asm/futex.h | |
150 | @@ -73,20 +73,11 @@ | |
151 | ||
152 | #endif | |
153 | ||
154 | -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
155 | +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, | |
156 | + u32 __user *uaddr) | |
157 | { | |
158 | - int op = (encoded_op >> 28) & 7; | |
159 | - int cmp = (encoded_op >> 24) & 15; | |
160 | - int oparg = (encoded_op << 8) >> 20; | |
161 | - int cmparg = (encoded_op << 20) >> 20; | |
162 | int oldval = 0, ret; | |
163 | ||
164 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
165 | - oparg = 1 << oparg; | |
166 | - | |
167 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) | |
168 | - return -EFAULT; | |
169 | - | |
170 | #ifndef CONFIG_ARC_HAS_LLSC | |
171 | preempt_disable(); /* to guarantee atomic r-m-w of futex op */ | |
172 | #endif | |
173 | @@ -118,30 +109,9 @@ static inline int futex_atomic_op_inuser | |
174 | preempt_enable(); | |
175 | #endif | |
176 | ||
177 | - if (!ret) { | |
178 | - switch (cmp) { | |
179 | - case FUTEX_OP_CMP_EQ: | |
180 | - ret = (oldval == cmparg); | |
181 | - break; | |
182 | - case FUTEX_OP_CMP_NE: | |
183 | - ret = (oldval != cmparg); | |
184 | - break; | |
185 | - case FUTEX_OP_CMP_LT: | |
186 | - ret = (oldval < cmparg); | |
187 | - break; | |
188 | - case FUTEX_OP_CMP_GE: | |
189 | - ret = (oldval >= cmparg); | |
190 | - break; | |
191 | - case FUTEX_OP_CMP_LE: | |
192 | - ret = (oldval <= cmparg); | |
193 | - break; | |
194 | - case FUTEX_OP_CMP_GT: | |
195 | - ret = (oldval > cmparg); | |
196 | - break; | |
197 | - default: | |
198 | - ret = -ENOSYS; | |
199 | - } | |
200 | - } | |
201 | + if (!ret) | |
202 | + *oval = oldval; | |
203 | + | |
204 | return ret; | |
205 | } | |
206 | ||
207 | --- a/arch/arm/include/asm/futex.h | |
208 | +++ b/arch/arm/include/asm/futex.h | |
209 | @@ -128,20 +128,10 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, | |
210 | #endif /* !SMP */ | |
211 | ||
212 | static inline int | |
213 | -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) | |
214 | +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) | |
215 | { | |
216 | - int op = (encoded_op >> 28) & 7; | |
217 | - int cmp = (encoded_op >> 24) & 15; | |
218 | - int oparg = (encoded_op << 8) >> 20; | |
219 | - int cmparg = (encoded_op << 20) >> 20; | |
220 | int oldval = 0, ret, tmp; | |
221 | ||
222 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
223 | - oparg = 1 << oparg; | |
224 | - | |
225 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
226 | - return -EFAULT; | |
227 | - | |
228 | #ifndef CONFIG_SMP | |
229 | preempt_disable(); | |
230 | #endif | |
231 | @@ -172,17 +162,9 @@ futex_atomic_op_inuser (int encoded_op, | |
232 | preempt_enable(); | |
233 | #endif | |
234 | ||
235 | - if (!ret) { | |
236 | - switch (cmp) { | |
237 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
238 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
239 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
240 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
241 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
242 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
243 | - default: ret = -ENOSYS; | |
244 | - } | |
245 | - } | |
246 | + if (!ret) | |
247 | + *oval = oldval; | |
248 | + | |
249 | return ret; | |
250 | } | |
251 | ||
252 | --- a/arch/arm64/include/asm/futex.h | |
253 | +++ b/arch/arm64/include/asm/futex.h | |
254 | @@ -53,20 +53,10 @@ | |
255 | : "memory") | |
256 | ||
257 | static inline int | |
258 | -futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr) | |
259 | +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) | |
260 | { | |
261 | - int op = (encoded_op >> 28) & 7; | |
262 | - int cmp = (encoded_op >> 24) & 15; | |
263 | - int oparg = (int)(encoded_op << 8) >> 20; | |
264 | - int cmparg = (int)(encoded_op << 20) >> 20; | |
265 | int oldval = 0, ret, tmp; | |
266 | ||
267 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
268 | - oparg = 1U << (oparg & 0x1f); | |
269 | - | |
270 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
271 | - return -EFAULT; | |
272 | - | |
273 | pagefault_disable(); | |
274 | ||
275 | switch (op) { | |
276 | @@ -96,17 +86,9 @@ futex_atomic_op_inuser(unsigned int enco | |
277 | ||
278 | pagefault_enable(); | |
279 | ||
280 | - if (!ret) { | |
281 | - switch (cmp) { | |
282 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
283 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
284 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
285 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
286 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
287 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
288 | - default: ret = -ENOSYS; | |
289 | - } | |
290 | - } | |
291 | + if (!ret) | |
292 | + *oval = oldval; | |
293 | + | |
294 | return ret; | |
295 | } | |
296 | ||
297 | --- a/arch/frv/include/asm/futex.h | |
298 | +++ b/arch/frv/include/asm/futex.h | |
299 | @@ -7,7 +7,8 @@ | |
300 | #include <asm/errno.h> | |
301 | #include <asm/uaccess.h> | |
302 | ||
303 | -extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr); | |
304 | +extern int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, | |
305 | + u32 __user *uaddr); | |
306 | ||
307 | static inline int | |
308 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | |
309 | --- a/arch/frv/kernel/futex.c | |
310 | +++ b/arch/frv/kernel/futex.c | |
311 | @@ -186,20 +186,10 @@ static inline int atomic_futex_op_xchg_x | |
312 | /* | |
313 | * do the futex operations | |
314 | */ | |
315 | -int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
316 | +int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) | |
317 | { | |
318 | - int op = (encoded_op >> 28) & 7; | |
319 | - int cmp = (encoded_op >> 24) & 15; | |
320 | - int oparg = (encoded_op << 8) >> 20; | |
321 | - int cmparg = (encoded_op << 20) >> 20; | |
322 | int oldval = 0, ret; | |
323 | ||
324 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
325 | - oparg = 1 << oparg; | |
326 | - | |
327 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
328 | - return -EFAULT; | |
329 | - | |
330 | pagefault_disable(); | |
331 | ||
332 | switch (op) { | |
333 | @@ -225,18 +215,9 @@ int futex_atomic_op_inuser(int encoded_o | |
334 | ||
335 | pagefault_enable(); | |
336 | ||
337 | - if (!ret) { | |
338 | - switch (cmp) { | |
339 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
340 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
341 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
342 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
343 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
344 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
345 | - default: ret = -ENOSYS; break; | |
346 | - } | |
347 | - } | |
348 | + if (!ret) | |
349 | + *oval = oldval; | |
350 | ||
351 | return ret; | |
352 | ||
353 | -} /* end futex_atomic_op_inuser() */ | |
354 | +} /* end arch_futex_atomic_op_inuser() */ | |
355 | --- a/arch/hexagon/include/asm/futex.h | |
356 | +++ b/arch/hexagon/include/asm/futex.h | |
357 | @@ -31,18 +31,9 @@ | |
358 | ||
359 | ||
360 | static inline int | |
361 | -futex_atomic_op_inuser(int encoded_op, int __user *uaddr) | |
362 | +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) | |
363 | { | |
364 | - int op = (encoded_op >> 28) & 7; | |
365 | - int cmp = (encoded_op >> 24) & 15; | |
366 | - int oparg = (encoded_op << 8) >> 20; | |
367 | - int cmparg = (encoded_op << 20) >> 20; | |
368 | int oldval = 0, ret; | |
369 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
370 | - oparg = 1 << oparg; | |
371 | - | |
372 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) | |
373 | - return -EFAULT; | |
374 | ||
375 | pagefault_disable(); | |
376 | ||
377 | @@ -72,30 +63,9 @@ futex_atomic_op_inuser(int encoded_op, i | |
378 | ||
379 | pagefault_enable(); | |
380 | ||
381 | - if (!ret) { | |
382 | - switch (cmp) { | |
383 | - case FUTEX_OP_CMP_EQ: | |
384 | - ret = (oldval == cmparg); | |
385 | - break; | |
386 | - case FUTEX_OP_CMP_NE: | |
387 | - ret = (oldval != cmparg); | |
388 | - break; | |
389 | - case FUTEX_OP_CMP_LT: | |
390 | - ret = (oldval < cmparg); | |
391 | - break; | |
392 | - case FUTEX_OP_CMP_GE: | |
393 | - ret = (oldval >= cmparg); | |
394 | - break; | |
395 | - case FUTEX_OP_CMP_LE: | |
396 | - ret = (oldval <= cmparg); | |
397 | - break; | |
398 | - case FUTEX_OP_CMP_GT: | |
399 | - ret = (oldval > cmparg); | |
400 | - break; | |
401 | - default: | |
402 | - ret = -ENOSYS; | |
403 | - } | |
404 | - } | |
405 | + if (!ret) | |
406 | + *oval = oldval; | |
407 | + | |
408 | return ret; | |
409 | } | |
410 | ||
411 | --- a/arch/ia64/include/asm/futex.h | |
412 | +++ b/arch/ia64/include/asm/futex.h | |
413 | @@ -45,18 +45,9 @@ do { \ | |
414 | } while (0) | |
415 | ||
416 | static inline int | |
417 | -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) | |
418 | +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) | |
419 | { | |
420 | - int op = (encoded_op >> 28) & 7; | |
421 | - int cmp = (encoded_op >> 24) & 15; | |
422 | - int oparg = (encoded_op << 8) >> 20; | |
423 | - int cmparg = (encoded_op << 20) >> 20; | |
424 | int oldval = 0, ret; | |
425 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
426 | - oparg = 1 << oparg; | |
427 | - | |
428 | - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) | |
429 | - return -EFAULT; | |
430 | ||
431 | pagefault_disable(); | |
432 | ||
433 | @@ -84,17 +75,9 @@ futex_atomic_op_inuser (int encoded_op, | |
434 | ||
435 | pagefault_enable(); | |
436 | ||
437 | - if (!ret) { | |
438 | - switch (cmp) { | |
439 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
440 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
441 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
442 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
443 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
444 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
445 | - default: ret = -ENOSYS; | |
446 | - } | |
447 | - } | |
448 | + if (!ret) | |
449 | + *oval = oldval; | |
450 | + | |
451 | return ret; | |
452 | } | |
453 | ||
454 | --- a/arch/microblaze/include/asm/futex.h | |
455 | +++ b/arch/microblaze/include/asm/futex.h | |
456 | @@ -29,18 +29,9 @@ | |
457 | }) | |
458 | ||
459 | static inline int | |
460 | -futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
461 | +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) | |
462 | { | |
463 | - int op = (encoded_op >> 28) & 7; | |
464 | - int cmp = (encoded_op >> 24) & 15; | |
465 | - int oparg = (encoded_op << 8) >> 20; | |
466 | - int cmparg = (encoded_op << 20) >> 20; | |
467 | int oldval = 0, ret; | |
468 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
469 | - oparg = 1 << oparg; | |
470 | - | |
471 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
472 | - return -EFAULT; | |
473 | ||
474 | pagefault_disable(); | |
475 | ||
476 | @@ -66,30 +57,9 @@ futex_atomic_op_inuser(int encoded_op, u | |
477 | ||
478 | pagefault_enable(); | |
479 | ||
480 | - if (!ret) { | |
481 | - switch (cmp) { | |
482 | - case FUTEX_OP_CMP_EQ: | |
483 | - ret = (oldval == cmparg); | |
484 | - break; | |
485 | - case FUTEX_OP_CMP_NE: | |
486 | - ret = (oldval != cmparg); | |
487 | - break; | |
488 | - case FUTEX_OP_CMP_LT: | |
489 | - ret = (oldval < cmparg); | |
490 | - break; | |
491 | - case FUTEX_OP_CMP_GE: | |
492 | - ret = (oldval >= cmparg); | |
493 | - break; | |
494 | - case FUTEX_OP_CMP_LE: | |
495 | - ret = (oldval <= cmparg); | |
496 | - break; | |
497 | - case FUTEX_OP_CMP_GT: | |
498 | - ret = (oldval > cmparg); | |
499 | - break; | |
500 | - default: | |
501 | - ret = -ENOSYS; | |
502 | - } | |
503 | - } | |
504 | + if (!ret) | |
505 | + *oval = oldval; | |
506 | + | |
507 | return ret; | |
508 | } | |
509 | ||
510 | --- a/arch/mips/include/asm/futex.h | |
511 | +++ b/arch/mips/include/asm/futex.h | |
512 | @@ -83,18 +83,9 @@ | |
513 | } | |
514 | ||
515 | static inline int | |
516 | -futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
517 | +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) | |
518 | { | |
519 | - int op = (encoded_op >> 28) & 7; | |
520 | - int cmp = (encoded_op >> 24) & 15; | |
521 | - int oparg = (encoded_op << 8) >> 20; | |
522 | - int cmparg = (encoded_op << 20) >> 20; | |
523 | int oldval = 0, ret; | |
524 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
525 | - oparg = 1 << oparg; | |
526 | - | |
527 | - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) | |
528 | - return -EFAULT; | |
529 | ||
530 | pagefault_disable(); | |
531 | ||
532 | @@ -125,17 +116,9 @@ futex_atomic_op_inuser(int encoded_op, u | |
533 | ||
534 | pagefault_enable(); | |
535 | ||
536 | - if (!ret) { | |
537 | - switch (cmp) { | |
538 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
539 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
540 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
541 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
542 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
543 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
544 | - default: ret = -ENOSYS; | |
545 | - } | |
546 | - } | |
547 | + if (!ret) | |
548 | + *oval = oldval; | |
549 | + | |
550 | return ret; | |
551 | } | |
552 | ||
553 | --- a/arch/parisc/include/asm/futex.h | |
554 | +++ b/arch/parisc/include/asm/futex.h | |
555 | @@ -32,20 +32,11 @@ _futex_spin_unlock_irqrestore(u32 __user | |
556 | } | |
557 | ||
558 | static inline int | |
559 | -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) | |
560 | +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) | |
561 | { | |
562 | unsigned long int flags; | |
563 | u32 val; | |
564 | - int op = (encoded_op >> 28) & 7; | |
565 | - int cmp = (encoded_op >> 24) & 15; | |
566 | - int oparg = (encoded_op << 8) >> 20; | |
567 | - int cmparg = (encoded_op << 20) >> 20; | |
568 | int oldval = 0, ret; | |
569 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
570 | - oparg = 1 << oparg; | |
571 | - | |
572 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr))) | |
573 | - return -EFAULT; | |
574 | ||
575 | pagefault_disable(); | |
576 | ||
577 | @@ -98,17 +89,9 @@ futex_atomic_op_inuser (int encoded_op, | |
578 | ||
579 | pagefault_enable(); | |
580 | ||
581 | - if (!ret) { | |
582 | - switch (cmp) { | |
583 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
584 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
585 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
586 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
587 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
588 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
589 | - default: ret = -ENOSYS; | |
590 | - } | |
591 | - } | |
592 | + if (!ret) | |
593 | + *oval = oldval; | |
594 | + | |
595 | return ret; | |
596 | } | |
597 | ||
598 | --- a/arch/powerpc/include/asm/futex.h | |
599 | +++ b/arch/powerpc/include/asm/futex.h | |
600 | @@ -31,18 +31,10 @@ | |
601 | : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \ | |
602 | : "cr0", "memory") | |
603 | ||
604 | -static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) | |
605 | +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, | |
606 | + u32 __user *uaddr) | |
607 | { | |
608 | - int op = (encoded_op >> 28) & 7; | |
609 | - int cmp = (encoded_op >> 24) & 15; | |
610 | - int oparg = (encoded_op << 8) >> 20; | |
611 | - int cmparg = (encoded_op << 20) >> 20; | |
612 | int oldval = 0, ret; | |
613 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
614 | - oparg = 1 << oparg; | |
615 | - | |
616 | - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) | |
617 | - return -EFAULT; | |
618 | ||
619 | pagefault_disable(); | |
620 | ||
621 | @@ -68,17 +60,9 @@ static inline int futex_atomic_op_inuser | |
622 | ||
623 | pagefault_enable(); | |
624 | ||
625 | - if (!ret) { | |
626 | - switch (cmp) { | |
627 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
628 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
629 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
630 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
631 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
632 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
633 | - default: ret = -ENOSYS; | |
634 | - } | |
635 | - } | |
636 | + if (!ret) | |
637 | + *oval = oldval; | |
638 | + | |
639 | return ret; | |
640 | } | |
641 | ||
642 | --- a/arch/s390/include/asm/futex.h | |
643 | +++ b/arch/s390/include/asm/futex.h | |
644 | @@ -21,17 +21,12 @@ | |
645 | : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ | |
646 | "m" (*uaddr) : "cc"); | |
647 | ||
648 | -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
649 | +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, | |
650 | + u32 __user *uaddr) | |
651 | { | |
652 | - int op = (encoded_op >> 28) & 7; | |
653 | - int cmp = (encoded_op >> 24) & 15; | |
654 | - int oparg = (encoded_op << 8) >> 20; | |
655 | - int cmparg = (encoded_op << 20) >> 20; | |
656 | int oldval = 0, newval, ret; | |
657 | ||
658 | load_kernel_asce(); | |
659 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
660 | - oparg = 1 << oparg; | |
661 | ||
662 | pagefault_disable(); | |
663 | switch (op) { | |
664 | @@ -60,17 +55,9 @@ static inline int futex_atomic_op_inuser | |
665 | } | |
666 | pagefault_enable(); | |
667 | ||
668 | - if (!ret) { | |
669 | - switch (cmp) { | |
670 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
671 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
672 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
673 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
674 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
675 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
676 | - default: ret = -ENOSYS; | |
677 | - } | |
678 | - } | |
679 | + if (!ret) | |
680 | + *oval = oldval; | |
681 | + | |
682 | return ret; | |
683 | } | |
684 | ||
685 | --- a/arch/sh/include/asm/futex.h | |
686 | +++ b/arch/sh/include/asm/futex.h | |
687 | @@ -10,20 +10,11 @@ | |
688 | /* XXX: UP variants, fix for SH-4A and SMP.. */ | |
689 | #include <asm/futex-irq.h> | |
690 | ||
691 | -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
692 | +static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, | |
693 | + u32 __user *uaddr) | |
694 | { | |
695 | - int op = (encoded_op >> 28) & 7; | |
696 | - int cmp = (encoded_op >> 24) & 15; | |
697 | - int oparg = (encoded_op << 8) >> 20; | |
698 | - int cmparg = (encoded_op << 20) >> 20; | |
699 | int oldval = 0, ret; | |
700 | ||
701 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
702 | - oparg = 1 << oparg; | |
703 | - | |
704 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
705 | - return -EFAULT; | |
706 | - | |
707 | pagefault_disable(); | |
708 | ||
709 | switch (op) { | |
710 | @@ -49,17 +40,8 @@ static inline int futex_atomic_op_inuser | |
711 | ||
712 | pagefault_enable(); | |
713 | ||
714 | - if (!ret) { | |
715 | - switch (cmp) { | |
716 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
717 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
718 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
719 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
720 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
721 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
722 | - default: ret = -ENOSYS; | |
723 | - } | |
724 | - } | |
725 | + if (!ret) | |
726 | + *oval = oldval; | |
727 | ||
728 | return ret; | |
729 | } | |
730 | --- a/arch/sparc/include/asm/futex_64.h | |
731 | +++ b/arch/sparc/include/asm/futex_64.h | |
732 | @@ -29,22 +29,14 @@ | |
733 | : "r" (uaddr), "r" (oparg), "i" (-EFAULT) \ | |
734 | : "memory") | |
735 | ||
736 | -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
737 | +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, | |
738 | + u32 __user *uaddr) | |
739 | { | |
740 | - int op = (encoded_op >> 28) & 7; | |
741 | - int cmp = (encoded_op >> 24) & 15; | |
742 | - int oparg = (encoded_op << 8) >> 20; | |
743 | - int cmparg = (encoded_op << 20) >> 20; | |
744 | int oldval = 0, ret, tem; | |
745 | ||
746 | - if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))) | |
747 | - return -EFAULT; | |
748 | if (unlikely((((unsigned long) uaddr) & 0x3UL))) | |
749 | return -EINVAL; | |
750 | ||
751 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
752 | - oparg = 1 << oparg; | |
753 | - | |
754 | pagefault_disable(); | |
755 | ||
756 | switch (op) { | |
757 | @@ -69,17 +61,9 @@ static inline int futex_atomic_op_inuser | |
758 | ||
759 | pagefault_enable(); | |
760 | ||
761 | - if (!ret) { | |
762 | - switch (cmp) { | |
763 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
764 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
765 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
766 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
767 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
768 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
769 | - default: ret = -ENOSYS; | |
770 | - } | |
771 | - } | |
772 | + if (!ret) | |
773 | + *oval = oldval; | |
774 | + | |
775 | return ret; | |
776 | } | |
777 | ||
778 | --- a/arch/tile/include/asm/futex.h | |
779 | +++ b/arch/tile/include/asm/futex.h | |
780 | @@ -106,12 +106,9 @@ | |
781 | lock = __atomic_hashed_lock((int __force *)uaddr) | |
782 | #endif | |
783 | ||
784 | -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
785 | +static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, | |
786 | + u32 __user *uaddr) | |
787 | { | |
788 | - int op = (encoded_op >> 28) & 7; | |
789 | - int cmp = (encoded_op >> 24) & 15; | |
790 | - int oparg = (encoded_op << 8) >> 20; | |
791 | - int cmparg = (encoded_op << 20) >> 20; | |
792 | int uninitialized_var(val), ret; | |
793 | ||
794 | __futex_prolog(); | |
795 | @@ -119,12 +116,6 @@ static inline int futex_atomic_op_inuser | |
796 | /* The 32-bit futex code makes this assumption, so validate it here. */ | |
797 | BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int)); | |
798 | ||
799 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
800 | - oparg = 1 << oparg; | |
801 | - | |
802 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
803 | - return -EFAULT; | |
804 | - | |
805 | pagefault_disable(); | |
806 | switch (op) { | |
807 | case FUTEX_OP_SET: | |
808 | @@ -148,30 +139,9 @@ static inline int futex_atomic_op_inuser | |
809 | } | |
810 | pagefault_enable(); | |
811 | ||
812 | - if (!ret) { | |
813 | - switch (cmp) { | |
814 | - case FUTEX_OP_CMP_EQ: | |
815 | - ret = (val == cmparg); | |
816 | - break; | |
817 | - case FUTEX_OP_CMP_NE: | |
818 | - ret = (val != cmparg); | |
819 | - break; | |
820 | - case FUTEX_OP_CMP_LT: | |
821 | - ret = (val < cmparg); | |
822 | - break; | |
823 | - case FUTEX_OP_CMP_GE: | |
824 | - ret = (val >= cmparg); | |
825 | - break; | |
826 | - case FUTEX_OP_CMP_LE: | |
827 | - ret = (val <= cmparg); | |
828 | - break; | |
829 | - case FUTEX_OP_CMP_GT: | |
830 | - ret = (val > cmparg); | |
831 | - break; | |
832 | - default: | |
833 | - ret = -ENOSYS; | |
834 | - } | |
835 | - } | |
836 | + if (!ret) | |
837 | + *oval = val; | |
838 | + | |
839 | return ret; | |
840 | } | |
841 | ||
842 | --- a/arch/x86/include/asm/futex.h | |
843 | +++ b/arch/x86/include/asm/futex.h | |
844 | @@ -41,20 +41,11 @@ | |
845 | "+m" (*uaddr), "=&r" (tem) \ | |
846 | : "r" (oparg), "i" (-EFAULT), "1" (0)) | |
847 | ||
848 | -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
849 | +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, | |
850 | + u32 __user *uaddr) | |
851 | { | |
852 | - int op = (encoded_op >> 28) & 7; | |
853 | - int cmp = (encoded_op >> 24) & 15; | |
854 | - int oparg = (encoded_op << 8) >> 20; | |
855 | - int cmparg = (encoded_op << 20) >> 20; | |
856 | int oldval = 0, ret, tem; | |
857 | ||
858 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
859 | - oparg = 1 << oparg; | |
860 | - | |
861 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
862 | - return -EFAULT; | |
863 | - | |
864 | pagefault_disable(); | |
865 | ||
866 | switch (op) { | |
867 | @@ -80,30 +71,9 @@ static inline int futex_atomic_op_inuser | |
868 | ||
869 | pagefault_enable(); | |
870 | ||
871 | - if (!ret) { | |
872 | - switch (cmp) { | |
873 | - case FUTEX_OP_CMP_EQ: | |
874 | - ret = (oldval == cmparg); | |
875 | - break; | |
876 | - case FUTEX_OP_CMP_NE: | |
877 | - ret = (oldval != cmparg); | |
878 | - break; | |
879 | - case FUTEX_OP_CMP_LT: | |
880 | - ret = (oldval < cmparg); | |
881 | - break; | |
882 | - case FUTEX_OP_CMP_GE: | |
883 | - ret = (oldval >= cmparg); | |
884 | - break; | |
885 | - case FUTEX_OP_CMP_LE: | |
886 | - ret = (oldval <= cmparg); | |
887 | - break; | |
888 | - case FUTEX_OP_CMP_GT: | |
889 | - ret = (oldval > cmparg); | |
890 | - break; | |
891 | - default: | |
892 | - ret = -ENOSYS; | |
893 | - } | |
894 | - } | |
895 | + if (!ret) | |
896 | + *oval = oldval; | |
897 | + | |
898 | return ret; | |
899 | } | |
900 | ||
901 | --- a/arch/xtensa/include/asm/futex.h | |
902 | +++ b/arch/xtensa/include/asm/futex.h | |
903 | @@ -44,18 +44,10 @@ | |
904 | : "r" (uaddr), "I" (-EFAULT), "r" (oparg) \ | |
905 | : "memory") | |
906 | ||
907 | -static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
908 | +static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, | |
909 | + u32 __user *uaddr) | |
910 | { | |
911 | - int op = (encoded_op >> 28) & 7; | |
912 | - int cmp = (encoded_op >> 24) & 15; | |
913 | - int oparg = (encoded_op << 8) >> 20; | |
914 | - int cmparg = (encoded_op << 20) >> 20; | |
915 | int oldval = 0, ret; | |
916 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
917 | - oparg = 1 << oparg; | |
918 | - | |
919 | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
920 | - return -EFAULT; | |
921 | ||
922 | #if !XCHAL_HAVE_S32C1I | |
923 | return -ENOSYS; | |
924 | @@ -89,19 +81,10 @@ static inline int futex_atomic_op_inuser | |
925 | ||
926 | pagefault_enable(); | |
927 | ||
928 | - if (ret) | |
929 | - return ret; | |
930 | - | |
931 | - switch (cmp) { | |
932 | - case FUTEX_OP_CMP_EQ: return (oldval == cmparg); | |
933 | - case FUTEX_OP_CMP_NE: return (oldval != cmparg); | |
934 | - case FUTEX_OP_CMP_LT: return (oldval < cmparg); | |
935 | - case FUTEX_OP_CMP_GE: return (oldval >= cmparg); | |
936 | - case FUTEX_OP_CMP_LE: return (oldval <= cmparg); | |
937 | - case FUTEX_OP_CMP_GT: return (oldval > cmparg); | |
938 | - } | |
939 | + if (!ret) | |
940 | + *oval = oldval; | |
941 | ||
942 | - return -ENOSYS; | |
943 | + return ret; | |
944 | } | |
945 | ||
946 | static inline int | |
947 | --- a/include/asm-generic/futex.h | |
948 | +++ b/include/asm-generic/futex.h | |
949 | @@ -13,7 +13,7 @@ | |
950 | */ | |
951 | ||
952 | /** | |
953 | - * futex_atomic_op_inuser() - Atomic arithmetic operation with constant | |
954 | + * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant | |
955 | * argument and comparison of the previous | |
956 | * futex value with another constant. | |
957 | * | |
958 | @@ -25,18 +25,11 @@ | |
959 | * <0 - On error | |
960 | */ | |
961 | static inline int | |
962 | -futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |
963 | +arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) | |
964 | { | |
965 | - int op = (encoded_op >> 28) & 7; | |
966 | - int cmp = (encoded_op >> 24) & 15; | |
967 | - int oparg = (encoded_op << 8) >> 20; | |
968 | - int cmparg = (encoded_op << 20) >> 20; | |
969 | int oldval, ret; | |
970 | u32 tmp; | |
971 | ||
972 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
973 | - oparg = 1 << oparg; | |
974 | - | |
975 | preempt_disable(); | |
976 | pagefault_disable(); | |
977 | ||
978 | @@ -74,17 +67,9 @@ out_pagefault_enable: | |
979 | pagefault_enable(); | |
980 | preempt_enable(); | |
981 | ||
982 | - if (ret == 0) { | |
983 | - switch (cmp) { | |
984 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
985 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
986 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
987 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
988 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
989 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
990 | - default: ret = -ENOSYS; | |
991 | - } | |
992 | - } | |
993 | + if (ret == 0) | |
994 | + *oval = oldval; | |
995 | + | |
996 | return ret; | |
997 | } | |
998 | ||
999 | @@ -126,18 +111,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, | |
1000 | ||
1001 | #else | |
1002 | static inline int | |
1003 | -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) | |
1004 | +arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) | |
1005 | { | |
1006 | - int op = (encoded_op >> 28) & 7; | |
1007 | - int cmp = (encoded_op >> 24) & 15; | |
1008 | - int oparg = (encoded_op << 8) >> 20; | |
1009 | - int cmparg = (encoded_op << 20) >> 20; | |
1010 | int oldval = 0, ret; | |
1011 | - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | |
1012 | - oparg = 1 << oparg; | |
1013 | - | |
1014 | - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32))) | |
1015 | - return -EFAULT; | |
1016 | ||
1017 | pagefault_disable(); | |
1018 | ||
1019 | @@ -153,17 +129,9 @@ futex_atomic_op_inuser (int encoded_op, | |
1020 | ||
1021 | pagefault_enable(); | |
1022 | ||
1023 | - if (!ret) { | |
1024 | - switch (cmp) { | |
1025 | - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | |
1026 | - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | |
1027 | - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | |
1028 | - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | |
1029 | - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | |
1030 | - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | |
1031 | - default: ret = -ENOSYS; | |
1032 | - } | |
1033 | - } | |
1034 | + if (!ret) | |
1035 | + *oval = oldval; | |
1036 | + | |
1037 | return ret; | |
1038 | } | |
1039 | ||
1040 | --- a/kernel/futex.c | |
1041 | +++ b/kernel/futex.c | |
1042 | @@ -1453,6 +1453,45 @@ out: | |
1043 | return ret; | |
1044 | } | |
1045 | ||
1046 | +static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr) | |
1047 | +{ | |
1048 | + unsigned int op = (encoded_op & 0x70000000) >> 28; | |
1049 | + unsigned int cmp = (encoded_op & 0x0f000000) >> 24; | |
1050 | + int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 12); | |
1051 | + int cmparg = sign_extend32(encoded_op & 0x00000fff, 12); | |
1052 | + int oldval, ret; | |
1053 | + | |
1054 | + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) { | |
1055 | + if (oparg < 0 || oparg > 31) | |
1056 | + return -EINVAL; | |
1057 | + oparg = 1 << oparg; | |
1058 | + } | |
1059 | + | |
1060 | + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | |
1061 | + return -EFAULT; | |
1062 | + | |
1063 | + ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr); | |
1064 | + if (ret) | |
1065 | + return ret; | |
1066 | + | |
1067 | + switch (cmp) { | |
1068 | + case FUTEX_OP_CMP_EQ: | |
1069 | + return oldval == cmparg; | |
1070 | + case FUTEX_OP_CMP_NE: | |
1071 | + return oldval != cmparg; | |
1072 | + case FUTEX_OP_CMP_LT: | |
1073 | + return oldval < cmparg; | |
1074 | + case FUTEX_OP_CMP_GE: | |
1075 | + return oldval >= cmparg; | |
1076 | + case FUTEX_OP_CMP_LE: | |
1077 | + return oldval <= cmparg; | |
1078 | + case FUTEX_OP_CMP_GT: | |
1079 | + return oldval > cmparg; | |
1080 | + default: | |
1081 | + return -ENOSYS; | |
1082 | + } | |
1083 | +} | |
1084 | + | |
1085 | /* | |
1086 | * Wake up all waiters hashed on the physical page that is mapped | |
1087 | * to this virtual address: |