summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/aim
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2009-10-31 17:59:24 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2009-10-31 17:59:24 +0000
commit2eaf4c92f434a16fd6242959edb7032ec765f7b8 (patch)
treeefca3b5c477973e7261489eb9ebe4042e7dd6001 /sys/powerpc/aim
parentb6af1984be90ac658f0d71054ed431d9a33f061d (diff)
downloadFreeBSD-src-2eaf4c92f434a16fd6242959edb7032ec765f7b8.zip
FreeBSD-src-2eaf4c92f434a16fd6242959edb7032ec765f7b8.tar.gz
Fix a race in casuword() exposed by csup. casuword() non-atomically read
the current value of its argument before atomically replacing it, which could occasionally return the wrong value on an SMP system. This resulted in user mutex operations hanging when using threaded applications.
Diffstat (limited to 'sys/powerpc/aim')
-rw-r--r--sys/powerpc/aim/copyinout.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/sys/powerpc/aim/copyinout.c b/sys/powerpc/aim/copyinout.c
index 4e9f777..e023b3f 100644
--- a/sys/powerpc/aim/copyinout.c
+++ b/sys/powerpc/aim/copyinout.c
@@ -347,8 +347,19 @@ casuword(volatile u_long *addr, u_long old, u_long new)
return (-1);
}
- val = *p;
- (void) atomic_cmpset_32((volatile uint32_t *)p, old, new);
+ __asm __volatile (
+ "1:\tlwarx %0, 0, %2\n\t" /* load old value */
+ "cmplw %3, %0\n\t" /* compare */
+ "bne 2f\n\t" /* exit if not equal */
+ "stwcx. %4, 0, %2\n\t" /* attempt to store */
+ "bne- 1b\n\t" /* spin if failed */
+ "b 3f\n\t" /* we've succeeded */
+ "2:\n\t"
+ "stwcx. %0, 0, %2\n\t" /* clear reservation (74xx) */
+ "3:\n\t"
+ : "=&r" (val), "=m" (*p)
+ : "r" (p), "r" (old), "r" (new), "m" (*p)
+ : "cc", "memory");
td->td_pcb->pcb_onfault = NULL;
OpenPOWER on IntegriCloud