[parisc-linux-cvs] linux-2.6 jejb

James Bottomley James.Bottomley at SteelEye.com
Sun Aug 15 08:20:55 MDT 2004


On Sun, 2004-08-15 at 10:17, James Bottomley wrote:
> CVSROOT:	/var/cvs
> Module name:	linux-2.6
> Changes by:	jejb	04/08/15 08:17:39
> 
> Modified files:
> 	.              : Makefile 
> 	arch/parisc/lib: bitops.c 
> 	include/asm-parisc: atomic.h bitops.h spinlock.h system.h 
> 
> Log message:
> Fix SMP f_list corruption problem.
> 
> This was rather subtle.  It turns out that gcc was doing a small
> amount of reordering around the file_lock because it doesn't see our
> spinlock implementation as being a barrier.  To fix this I
> 
> - Added the appropriate barriers to all the spinlocks.
> - Removed the atomic opencoded spinlock and redid it as a proper one.
> 
> SMP now seems stable on a 2xA500 and has survived a 10 hour 35 loop
> make -j 4 kernel compile without showing any problems (previously, it
> usually fell over in the first loop).

Index: arch/parisc/lib/bitops.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/lib/bitops.c,v
retrieving revision 1.3
diff -u -r1.3 bitops.c
--- arch/parisc/lib/bitops.c	28 Jul 2004 16:57:53 -0000	1.3
+++ arch/parisc/lib/bitops.c	15 Aug 2004 14:13:12 -0000
@@ -13,8 +13,8 @@
 #include <asm/atomic.h>
 
 #ifdef CONFIG_SMP
-atomic_lock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = {
-	[0 ... (ATOMIC_HASH_SIZE-1)]  = (atomic_lock_t) { { 1, 1, 1, 1 } }
+spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = {
+	[0 ... (ATOMIC_HASH_SIZE-1)]  = SPIN_LOCK_UNLOCKED
 };
 #endif
 
@@ -23,10 +23,10 @@
 {
 	unsigned long temp, flags;
 
-	atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_lock_irqsave(ptr, flags);
 	temp = *ptr;
 	*ptr = x;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_unlock_irqrestore(ptr, flags);
 	return temp;
 }
 #endif
@@ -36,10 +36,10 @@
 	unsigned long flags;
 	long temp;
 
-	atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_lock_irqsave(ptr, flags);
 	temp = (long) *ptr;	/* XXX - sign extension wanted? */
 	*ptr = x;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_unlock_irqrestore(ptr, flags);
 	return (unsigned long)temp;
 }
 
@@ -49,10 +49,10 @@
 	unsigned long flags;
 	long temp;
 
-	atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_lock_irqsave(ptr, flags);
 	temp = (long) *ptr;	/* XXX - sign extension wanted? */
 	*ptr = x;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_unlock_irqrestore(ptr, flags);
 	return (unsigned long)temp;
 }
 
@@ -63,10 +63,10 @@
 	unsigned long flags;
 	unsigned long prev;
 
-	atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_lock_irqsave(ptr, flags);
 	if ((prev = *ptr) == old)
 		*ptr = new;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_unlock_irqrestore(ptr, flags);
 	return prev;
 }
 #endif
@@ -76,9 +76,9 @@
 	unsigned long flags;
 	unsigned int prev;
 
-	atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_lock_irqsave(ptr, flags);
 	if ((prev = *ptr) == old)
 		*ptr = new;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
+	_atomic_spin_unlock_irqrestore(ptr, flags);
 	return (unsigned long)prev;
 }
Index: include/asm-parisc/atomic.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/atomic.h,v
retrieving revision 1.8
diff -u -r1.8 atomic.h
--- include/asm-parisc/atomic.h	23 May 2004 23:53:01 -0000	1.8
+++ include/asm-parisc/atomic.h	15 Aug 2004 14:13:22 -0000
@@ -2,7 +2,7 @@
 #define _ASM_PARISC_ATOMIC_H_
 
 #include <linux/config.h>
-#include <asm/system.h>
+#include <asm/spinlock.h>
 /* Copyright (C) 2000 Philipp Rumpf <prumpf at tux.org>.  */
 
 /*
@@ -16,8 +16,6 @@
 #ifdef CONFIG_SMP
 #include <asm/cache.h>		/* we use L1_CACHE_BYTES */
 
-typedef spinlock_t atomic_lock_t;
-
 /* Use an array of spinlocks for our atomic_ts.
  * Hash function to index into a different SPINLOCK.
  * Since "a" is usually an address, use one spinlock per cacheline.
@@ -25,37 +23,28 @@
 #  define ATOMIC_HASH_SIZE 4
 #  define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ]))
 
-extern atomic_lock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
+extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
 
-static inline void atomic_spin_lock(atomic_lock_t *a)
-{
-	while (__ldcw(a) == 0)
-		while (a->lock[0] == 0);
-}
+/* Can't use _raw_spin_lock_irq because of #include problems, so
+ * this is the substitute */
+#define _atomic_spin_lock_irqsave(l,f) do {	\
+	spinlock_t *s = ATOMIC_HASH(l);		\
+	local_irq_save(f);			\
+	_raw_spin_lock(s);			\
+} while(0)
+
+#define _atomic_spin_unlock_irqrestore(l,f) do {	\
+	spinlock_t *s = ATOMIC_HASH(l);			\
+	_raw_spin_unlock(s);				\
+	local_irq_restore(f);				\
+} while(0)
 
-static inline void atomic_spin_unlock(atomic_lock_t *a)
-{
-	a->lock[0] = 1;
-}
 
 #else
 #  define ATOMIC_HASH_SIZE 1
 #  define ATOMIC_HASH(a)	(0)
-#  define atomic_spin_lock(x) (void)(x)
-#  define atomic_spin_unlock(x) do { } while(0)
 #endif
 
-/* copied from <linux/spinlock.h> and modified */
-#define atomic_spin_lock_irqsave(lock, flags)	do { 	\
-	local_irq_save(flags);				\
-	atomic_spin_lock(lock); 			\
-} while (0)
-
-#define atomic_spin_unlock_irqrestore(lock, flags) do {	\
-	atomic_spin_unlock(lock);			\
-	local_irq_restore(flags);			\
-} while (0)
-
 /* Note that we need not lock read accesses - aligned word writes/reads
  * are atomic, so a reader never sees unconsistent values.
  *
@@ -150,22 +139,22 @@
 {
 	int ret;
 	unsigned long flags;
-	atomic_spin_lock_irqsave(ATOMIC_HASH(v), flags);
+	_atomic_spin_lock_irqsave(v, flags);
 
 	ret = (v->counter += i);
 
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+	_atomic_spin_unlock_irqrestore(v, flags);
 	return ret;
 }
 
 static __inline__ void atomic_set(atomic_t *v, int i) 
 {
 	unsigned long flags;
-	atomic_spin_lock_irqsave(ATOMIC_HASH(v), flags);
+	_atomic_spin_lock_irqsave(v, flags);
 
 	v->counter = i;
 
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+	_atomic_spin_unlock_irqrestore(v, flags);
 }
 
 static __inline__ int atomic_read(const atomic_t *v)
Index: include/asm-parisc/bitops.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/bitops.h,v
retrieving revision 1.12
diff -u -r1.12 bitops.h
--- include/asm-parisc/bitops.h	13 Jul 2004 05:36:36 -0000	1.12
+++ include/asm-parisc/bitops.h	15 Aug 2004 14:13:22 -0000
@@ -38,9 +38,9 @@
 
 	addr += (nr >> SHIFT_PER_LONG);
 	mask = 1L << CHOP_SHIFTCOUNT(nr);
-	atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
+	_atomic_spin_lock_irqsave(addr, flags);
 	*addr |= mask;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
+	_atomic_spin_unlock_irqrestore(addr, flags);
 }
 
 static __inline__ void __set_bit(int nr, volatile unsigned long * address)
@@ -61,9 +61,9 @@
 
 	addr += (nr >> SHIFT_PER_LONG);
 	mask = 1L << CHOP_SHIFTCOUNT(nr);
-	atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
+	_atomic_spin_lock_irqsave(addr, flags);
 	*addr &= ~mask;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
+	_atomic_spin_unlock_irqrestore(addr, flags);
 }
 
 static __inline__ void __clear_bit(unsigned long nr, volatile unsigned long * address)
@@ -84,9 +84,9 @@
 
 	addr += (nr >> SHIFT_PER_LONG);
 	mask = 1L << CHOP_SHIFTCOUNT(nr);
-	atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
+	_atomic_spin_lock_irqsave(addr, flags);
 	*addr ^= mask;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
+	_atomic_spin_unlock_irqrestore(addr, flags);
 }
 
 static __inline__ void __change_bit(int nr, volatile unsigned long * address)
@@ -108,10 +108,10 @@
 
 	addr += (nr >> SHIFT_PER_LONG);
 	mask = 1L << CHOP_SHIFTCOUNT(nr);
-	atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
+	_atomic_spin_lock_irqsave(addr, flags);
 	oldbit = (*addr & mask) ? 1 : 0;
 	*addr |= mask;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
+	_atomic_spin_unlock_irqrestore(addr, flags);
 
 	return oldbit;
 }
@@ -139,10 +139,10 @@
 
 	addr += (nr >> SHIFT_PER_LONG);
 	mask = 1L << CHOP_SHIFTCOUNT(nr);
-	atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
+	_atomic_spin_lock_irqsave(addr, flags);
 	oldbit = (*addr & mask) ? 1 : 0;
 	*addr &= ~mask;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
+	_atomic_spin_unlock_irqrestore(addr, flags);
 
 	return oldbit;
 }
@@ -170,10 +170,10 @@
 
 	addr += (nr >> SHIFT_PER_LONG);
 	mask = 1L << CHOP_SHIFTCOUNT(nr);
-	atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
+	_atomic_spin_lock_irqsave(addr, flags);
 	oldbit = (*addr & mask) ? 1 : 0;
 	*addr ^= mask;
-	atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
+	_atomic_spin_unlock_irqrestore(addr, flags);
 
 	return oldbit;
 }
Index: include/asm-parisc/spinlock.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/spinlock.h,v
retrieving revision 1.5
diff -u -r1.5 spinlock.h
--- include/asm-parisc/spinlock.h	8 Jul 2004 17:16:21 -0000	1.5
+++ include/asm-parisc/spinlock.h	15 Aug 2004 14:13:22 -0000
@@ -27,21 +27,35 @@
 
 static inline void _raw_spin_lock(spinlock_t *x)
 {
-	volatile unsigned int *a = __ldcw_align(x);
+	volatile unsigned int *a;
+
+	mb();
+	a = __ldcw_align(x);
 	while (__ldcw(a) == 0)
 		while (*a == 0);
+	mb();
 }
 
 static inline void _raw_spin_unlock(spinlock_t *x)
 {
-	volatile unsigned int *a = __ldcw_align(x);
+	volatile unsigned int *a;
+	mb();
+	a = __ldcw_align(x);
 	*a = 1;
+	mb();
 }
 
 static inline int _raw_spin_trylock(spinlock_t *x)
 {
-	volatile unsigned int *a = __ldcw_align(x);
-	return __ldcw(a) != 0;
+	volatile unsigned int *a;
+	int ret;
+
+	mb();
+	a = __ldcw_align(x);
+        ret = __ldcw(a) != 0;
+	mb();
+
+	return ret;
 }
 	
 #define spin_lock_own(LOCK, LOCATION)	((void)0)
Index: include/asm-parisc/system.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/system.h,v
retrieving revision 1.4
diff -u -r1.4 system.h
--- include/asm-parisc/system.h	1 Jul 2004 18:30:37 -0000	1.4
+++ include/asm-parisc/system.h	15 Aug 2004 14:13:22 -0000
@@ -154,7 +154,7 @@
    for the semaphore.  */
 #define __PA_LDCW_ALIGNMENT 16
 #define __ldcw_align(a) ({ \
-  unsigned long __ret = (unsigned long) a;                     		\
+  unsigned long __ret = (unsigned long) &a->lock[0];                     		\
   __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); \
   (volatile unsigned int *) __ret;                                      \
 })



More information about the parisc-linux-cvs mailing list