diff options
author | xxie <xxie@nvidia.com> | 2011-01-31 20:03:45 -0800 |
---|---|---|
committer | Niket Sirsi <nsirsi@nvidia.com> | 2011-05-25 15:57:59 -0700 |
commit | 9b8f82db8279b0add89e3ef4fc06f3d23c2fce80 (patch) | |
tree | 59fcd75073d6d1f750d8eedd659c0d59cfd15dc5 /arch/arm/kernel | |
parent | 30015f8be08a183d4942d9849fa38e97754f36cd (diff) |
ARM: Fix strex() in SWP emulation
Found an application hanging using this SWP emulation on a SMP system.
A memory barrier is needed right after the strex() otherwise we have the
synchronization issues on SMP.
This patch let ldrex()+strex()+memory_barrier() loop continuesly until
the strex() is successful, this is same as ARM kernel spinlock
implementation and Bionic library's mutex's SWP() routine.
Tested the new implementation in a user space program running 100 threads
using the SWP based mutex on SMP systems, it did not show any race
conditions.
Change-Id: Ib5de14ba41a3fdb31510752114990be9ef35e144
Reviewed-on: http://git-master/r/29745
Reviewed-by: Xin Xie <xxie@nvidia.com>
Tested-by: Xin Xie <xxie@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/swp_emulate.c | 48 |
1 files changed, 17 insertions, 31 deletions
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index 7a5760922914..8fbb954da483 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -36,12 +36,13 @@ " mov %2, %1\n" \ "0: ldrex"B" %1, [%3]\n" \ "1: strex"B" %0, %2, [%3]\n" \ - " cmp %0, #0\n" \ - " movne %0, %4\n" \ + " dmb\n" \ + " teq %0, #0\n" \ + " bne 0b\n" \ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ - "3: mov %0, %5\n" \ + "3: mov %0, %4\n" \ " b 2b\n" \ " .previous\n" \ " .section __ex_table,\"a\"\n" \ @@ -50,7 +51,7 @@ " .long 1b, 3b\n" \ " .previous" \ : "=&r" (res), "+r" (data), "=&r" (temp) \ - : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ + : "r" (addr), "i" (-EFAULT) \ : "cc", "memory") #define __user_swp_asm(data, addr, res, temp) \ @@ -127,6 +128,7 @@ static int emulate_swpX(unsigned int address, unsigned int *data, unsigned int type) { unsigned int res = 0; + unsigned long temp; if ((type != TYPE_SWPB) && (address & 0x3)) { /* SWP to unaligned address not permitted */ @@ -134,36 +136,20 @@ static int emulate_swpX(unsigned int address, unsigned int *data, return -EFAULT; } - while (1) { - unsigned long temp; + /* + * Barrier required between accessing protected resource and + * releasing a lock for it. Legacy code might not have done + * this, and we cannot determine that this is not the case + * being emulated, so insert always. + */ + smp_mb(); - /* - * Barrier required between accessing protected resource and - * releasing a lock for it. Legacy code might not have done - * this, and we cannot determine that this is not the case - * being emulated, so insert always. - */ - smp_mb(); - - if (type == TYPE_SWPB) - __user_swpb_asm(*data, address, res, temp); - else - __user_swp_asm(*data, address, res, temp); - - if (likely(res != -EAGAIN) || signal_pending(current)) - break; - - cond_resched(); - } + if (type == TYPE_SWPB) + __user_swpb_asm(*data, address, res, temp); + else + __user_swp_asm(*data, address, res, temp); if (res == 0) { - /* - * Barrier also required between aquiring a lock for a - * protected resource and accessing the resource. Inserted for - * same reason as above. - */ - smp_mb(); - if (type == TYPE_SWPB) swpbcounter++; else |