diff -urN 2.4.4/include/asm-alpha/atomic.h softirq-race/include/asm-alpha/atomic.h --- 2.4.4/include/asm-alpha/atomic.h Tue Nov 28 18:40:01 2000 +++ softirq-race/include/asm-alpha/atomic.h Mon Apr 30 15:39:45 2001 @@ -106,4 +106,9 @@ #define atomic_inc(v) atomic_add(1,(v)) #define atomic_dec(v) atomic_sub(1,(v)) +#define smp_mb__before_atomic_inc() smp_mb() +#define smp_mb__after_atomic_inc() smp_mb() +#define smp_mb__before_atomic_dec() smp_mb() +#define smp_mb__after_atomic_dec() smp_mb() + #endif /* _ALPHA_ATOMIC_H */ diff -urN 2.4.4/include/asm-arm/atomic.h softirq-race/include/asm-arm/atomic.h --- 2.4.4/include/asm-arm/atomic.h Thu Nov 16 15:37:32 2000 +++ softirq-race/include/asm-arm/atomic.h Mon Apr 30 15:39:47 2001 @@ -36,6 +36,11 @@ #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + static __inline__ void atomic_add(int i, volatile atomic_t *v) { unsigned long flags; diff -urN 2.4.4/include/asm-cris/atomic.h softirq-race/include/asm-cris/atomic.h --- 2.4.4/include/asm-cris/atomic.h Thu Feb 22 03:45:11 2001 +++ softirq-race/include/asm-cris/atomic.h Mon Apr 30 15:39:47 2001 @@ -25,6 +25,11 @@ #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + /* These should be written in asm but we do it in C for now. */ static __inline__ void atomic_add(int i, volatile atomic_t *v) diff -urN 2.4.4/include/asm-i386/atomic.h softirq-race/include/asm-i386/atomic.h --- 2.4.4/include/asm-i386/atomic.h Sat Apr 28 05:24:45 2001 +++ softirq-race/include/asm-i386/atomic.h Mon Apr 30 15:39:45 2001 @@ -42,6 +42,15 @@ */ #define atomic_set(v,i) (((v)->counter) = (i)) +/* + * It maybe we need an explicit serialization across inc/dec on + * recent chips, if not then just replace this with a barrier(). + */ +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + /** * atomic_add - add integer to atomic variable * @i: integer value to add diff -urN 2.4.4/include/asm-ia64/atomic.h softirq-race/include/asm-ia64/atomic.h --- 2.4.4/include/asm-ia64/atomic.h Thu Nov 16 15:37:42 2000 +++ softirq-race/include/asm-ia64/atomic.h Mon Apr 30 15:39:47 2001 @@ -27,6 +27,11 @@ #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + static __inline__ int ia64_atomic_add (int i, atomic_t *v) { diff -urN 2.4.4/include/asm-m68k/atomic.h softirq-race/include/asm-m68k/atomic.h --- 2.4.4/include/asm-m68k/atomic.h Fri Nov 20 20:43:55 1998 +++ softirq-race/include/asm-m68k/atomic.h Mon Apr 30 15:39:47 2001 @@ -16,6 +16,11 @@ #define atomic_read(v) ((v)->counter) #define atomic_set(v, i) (((v)->counter) = i) +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + static __inline__ void atomic_add(int i, atomic_t *v) { __asm__ __volatile__("addl %1,%0" : "=m" (*v) : "id" (i), "0" (*v)); diff -urN 2.4.4/include/asm-mips/atomic.h softirq-race/include/asm-mips/atomic.h --- 2.4.4/include/asm-mips/atomic.h Sat May 13 17:31:25 2000 +++ softirq-race/include/asm-mips/atomic.h Mon Apr 30 15:39:47 2001 @@ -30,6 +30,11 @@ #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) ((v)->counter = (i)) +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + #if !defined(CONFIG_CPU_HAS_LLSC) #include diff -urN 2.4.4/include/asm-mips64/atomic.h softirq-race/include/asm-mips64/atomic.h --- 2.4.4/include/asm-mips64/atomic.h Thu Dec 14 22:34:13 2000 +++ softirq-race/include/asm-mips64/atomic.h Mon Apr 30 15:39:47 2001 @@ -24,6 +24,11 @@ #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) ((v)->counter = (i)) +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + extern __inline__ void atomic_add(int i, volatile atomic_t * v) { unsigned long temp; diff -urN 2.4.4/include/asm-parisc/atomic.h softirq-race/include/asm-parisc/atomic.h --- 2.4.4/include/asm-parisc/atomic.h Thu Dec 14 22:34:13 2000 +++ softirq-race/include/asm-parisc/atomic.h Mon Apr 30 15:39:47 2001 @@ -50,6 +50,10 @@ volatile int counter; } atomic_t; +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() /* It's possible to reduce all atomic operations to either * __atomic_add_return, __atomic_set and __atomic_ret (the latter * is there only for consistency). */ @@ -99,5 +103,10 @@ #define atomic_read(v) (__atomic_read(v)) #define ATOMIC_INIT(i) { (i) } + +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() #endif diff -urN 2.4.4/include/asm-ppc/atomic.h softirq-race/include/asm-ppc/atomic.h --- 2.4.4/include/asm-ppc/atomic.h Thu Nov 16 15:37:33 2000 +++ softirq-race/include/asm-ppc/atomic.h Mon Apr 30 15:39:47 2001 @@ -12,6 +12,11 @@ #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + extern void atomic_clear_mask(unsigned long mask, unsigned long *addr); extern void atomic_set_mask(unsigned long mask, unsigned long *addr); diff -urN 2.4.4/include/asm-s390/atomic.h softirq-race/include/asm-s390/atomic.h --- 2.4.4/include/asm-s390/atomic.h Sat Apr 28 05:24:46 2001 +++ softirq-race/include/asm-s390/atomic.h Mon Apr 30 15:39:47 2001 @@ -23,6 +23,11 @@ typedef struct { volatile int counter; } atomic_t __attribute__ ((aligned (4))); #define ATOMIC_INIT(i) { (i) } +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + #define atomic_eieio() __asm__ __volatile__ ("BCR 15,0") #define __CS_LOOP(old, new, ptr, op_val, op_string) \ diff -urN 2.4.4/include/asm-s390x/atomic.h softirq-race/include/asm-s390x/atomic.h --- 2.4.4/include/asm-s390x/atomic.h Sat Apr 28 05:24:46 2001 +++ softirq-race/include/asm-s390x/atomic.h Mon Apr 30 15:39:47 2001 @@ -23,6 +23,11 @@ typedef struct { volatile int counter; } atomic_t __attribute__ ((aligned (4))); #define ATOMIC_INIT(i) { (i) } +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + #define atomic_eieio() __asm__ __volatile__ ("BCR 15,0") #define __CS_LOOP(old, new, ptr, op_val, op_string) \ diff -urN 2.4.4/include/asm-sh/atomic.h softirq-race/include/asm-sh/atomic.h --- 2.4.4/include/asm-sh/atomic.h Thu Nov 16 15:37:33 2000 +++ softirq-race/include/asm-sh/atomic.h Mon Apr 30 15:39:47 2001 @@ -14,6 +14,11 @@ #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) ((v)->counter = (i)) +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + #include /* diff -urN 2.4.4/include/asm-sparc/atomic.h softirq-race/include/asm-sparc/atomic.h --- 2.4.4/include/asm-sparc/atomic.h Sun Apr 1 01:17:32 2001 +++ softirq-race/include/asm-sparc/atomic.h Mon Apr 30 15:39:47 2001 @@ -48,6 +48,11 @@ #define atomic_set(v, i) (((v)->counter) = ((i) << 8)) #endif +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + static __inline__ int __atomic_add(int i, atomic_t *v) { register volatile int *ptr asm("g1"); diff -urN 2.4.4/include/asm-sparc64/atomic.h softirq-race/include/asm-sparc64/atomic.h --- 2.4.4/include/asm-sparc64/atomic.h Thu Nov 16 15:37:42 2000 +++ softirq-race/include/asm-sparc64/atomic.h Mon Apr 30 15:39:47 2001 @@ -14,6 +14,11 @@ #define atomic_read(v) ((v)->counter) #define atomic_set(v, i) (((v)->counter) = i) +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + extern int __atomic_add(int, atomic_t *); extern int __atomic_sub(int, atomic_t *); diff -urN 2.4.4/include/linux/interrupt.h softirq-race/include/linux/interrupt.h --- 2.4.4/include/linux/interrupt.h Tue Apr 24 06:15:35 2001 +++ softirq-race/include/linux/interrupt.h Mon Apr 30 15:39:45 2001 @@ -186,16 +186,20 @@ static inline void tasklet_disable_nosync(struct tasklet_struct *t) { atomic_inc(&t->count); + smp_mb__after_atomic_inc(); } static inline void tasklet_disable(struct tasklet_struct *t) { tasklet_disable_nosync(t); tasklet_unlock_wait(t); + /* Make sure not to speculate reads until the tasklet resigns. */ + smp_rmb(); } static inline void tasklet_enable(struct tasklet_struct *t) { + smp_mb__before_atomic_dec(); atomic_dec(&t->count); } diff -urN 2.4.4/kernel/softirq.c softirq-race/kernel/softirq.c --- 2.4.4/kernel/softirq.c Tue Jan 2 17:41:22 2001 +++ softirq-race/kernel/softirq.c Mon Apr 30 15:39:45 2001 @@ -142,9 +142,15 @@ t->func(t->data); /* - * talklet_trylock() uses test_and_set_bit that imply + * talklet_trylock() uses test_and_set_bit that _just_ imply * an mb when it returns zero, thus we need the explicit * mb only here: while closing the critical section. + * + * On UP the barrier() in not necessary because f->func + * cannot be reordered by the compiler anyways because + * of the C language. Unless the compiler is doing something + * stupid dropping the #ifdef wouldn't make any difference in the + * generatd asm though (the #ifdef is mostly a documenetation issue). */ #ifdef CONFIG_SMP smp_mb__before_clear_bit(); @@ -152,6 +158,13 @@ tasklet_unlock(t); continue; } + /* + * NOTE: here we don't need the smb_mb() because the tasklet_unlock() + * write depends on the read of the &t->count that is in turn _the_ + * variable that the lock is serializing. The CPU isn't allowed to + * write to the memory before we checked t->count is not zero and + * by that time we don't need the lock any longer. + */ tasklet_unlock(t); } local_irq_disable(); @@ -186,6 +199,9 @@ clear_bit(TASKLET_STATE_SCHED, &t->state); t->func(t->data); +#ifdef CONFIG_SMP + smp_mb__before_clear_bit(); +#endif tasklet_unlock(t); continue; }