diff options
author | Nicolas Pitre <nico@cam.org> | 2007-11-20 11:20:29 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-11-26 14:43:58 -0500 |
commit | b49c0f24cf6744a3f4fd09289fe7cade349dead5 (patch) | |
tree | 23d244eae940f2e36a9bc1a2e77b8f1cc53e071a /arch/arm/kernel/traps.c | |
parent | aeb747afb3fb1f42d9c82615a103882f7f97f291 (diff) |
[ARM] 4659/1: remove possibilities for spurious false negative with __kuser_cmpxchg
The ARM __kuser_cmpxchg routine is meant to implement an atomic cmpxchg
in user space. It however can produce spurious false negative if a
processor exception occurs in the middle of the operation. Normally
this is not a problem since cmpxchg is typically called in a loop until
it succeeds to implement an atomic increment for example.
Some use cases which don't involve a loop require that the operation be
100% reliable though. This patch changes the implementation so to
reattempt the operation after an exception has occurred in the critical
section rather than abort it.
Here's a simple program to test the fix (don't use CONFIG_NO_HZ in your
kernel as this depends on a sufficiently high interrupt rate):
#include <stdio.h>
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
int main()
{
int i, x = 0;
for (i = 0; i < 100000000; i++) {
int v = x;
if (__kernel_cmpxchg(v, v+1, &x))
printf("failed at %d: %d vs %d\n", i, v, x);
}
printf("done with %d vs %d\n", i, x);
return 0;
}
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel/traps.c')
-rw-r--r-- | arch/arm/kernel/traps.c | 3 |
1 files changed, 1 insertions, 2 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 5a52dd7f97fe..c34db4e868fa 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -509,7 +509,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) | |||
509 | * existence. Don't ever use this from user code. | 509 | * existence. Don't ever use this from user code. |
510 | */ | 510 | */ |
511 | case 0xfff0: | 511 | case 0xfff0: |
512 | { | 512 | for (;;) { |
513 | extern void do_DataAbort(unsigned long addr, unsigned int fsr, | 513 | extern void do_DataAbort(unsigned long addr, unsigned int fsr, |
514 | struct pt_regs *regs); | 514 | struct pt_regs *regs); |
515 | unsigned long val; | 515 | unsigned long val; |
@@ -545,7 +545,6 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) | |||
545 | up_read(&mm->mmap_sem); | 545 | up_read(&mm->mmap_sem); |
546 | /* simulate a write access fault */ | 546 | /* simulate a write access fault */ |
547 | do_DataAbort(addr, 15 + (1 << 11), regs); | 547 | do_DataAbort(addr, 15 + (1 << 11), regs); |
548 | return -1; | ||
549 | } | 548 | } |
550 | #endif | 549 | #endif |
551 | 550 | ||