Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking fixes from Thomas Gleixner:
"Three patches to fix memory ordering issues on ALPHA and a comment to
clarify the usage scope of a mutex internal function"

* 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
locking/xchg/alpha: Fix xchg() and cmpxchg() memory ordering bugs
locking/xchg/alpha: Clean up barrier usage by using smp_mb() in place of __ASM__MB
locking/xchg/alpha: Add unconditional memory barrier to cmpxchg()
locking/mutex: Add comment to __mutex_owner() to deter usage

Changed files
+31 -18
arch
alpha
include
include
linux
-6
arch/alpha/include/asm/cmpxchg.h
··· 6 6 * Atomic exchange routines. 7 7 */ 8 8 9 - #define __ASM__MB 10 9 #define ____xchg(type, args...) __xchg ## type ## _local(args) 11 10 #define ____cmpxchg(type, args...) __cmpxchg ## type ## _local(args) 12 11 #include <asm/xchg.h> ··· 32 33 cmpxchg_local((ptr), (o), (n)); \ 33 34 }) 34 35 35 - #ifdef CONFIG_SMP 36 - #undef __ASM__MB 37 - #define __ASM__MB "\tmb\n" 38 - #endif 39 36 #undef ____xchg 40 37 #undef ____cmpxchg 41 38 #define ____xchg(type, args...) __xchg ##type(args) ··· 59 64 cmpxchg((ptr), (o), (n)); \ 60 65 }) 61 66 62 - #undef __ASM__MB 63 67 #undef ____cmpxchg 64 68 65 69 #endif /* _ALPHA_CMPXCHG_H */
+26 -12
arch/alpha/include/asm/xchg.h
··· 12 12 * Atomic exchange. 13 13 * Since it can be used to implement critical sections 14 14 * it must clobber "memory" (also for interrupts in UP). 15 + * 16 + * The leading and the trailing memory barriers guarantee that these 17 + * operations are fully ordered. 18 + * 15 19 */ 16 20 17 21 static inline unsigned long ··· 23 19 { 24 20 unsigned long ret, tmp, addr64; 25 21 22 + smp_mb(); 26 23 __asm__ __volatile__( 27 24 " andnot %4,7,%3\n" 28 25 " insbl %1,%4,%1\n" ··· 33 28 " or %1,%2,%2\n" 34 29 " stq_c %2,0(%3)\n" 35 30 " beq %2,2f\n" 36 - __ASM__MB 37 31 ".subsection 2\n" 38 32 "2: br 1b\n" 39 33 ".previous" 40 34 : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64) 41 35 : "r" ((long)m), "1" (val) : "memory"); 36 + smp_mb(); 42 37 43 38 return ret; 44 39 } ··· 48 43 { 49 44 unsigned long ret, tmp, addr64; 50 45 46 + smp_mb(); 51 47 __asm__ __volatile__( 52 48 " andnot %4,7,%3\n" 53 49 " inswl %1,%4,%1\n" ··· 58 52 " or %1,%2,%2\n" 59 53 " stq_c %2,0(%3)\n" 60 54 " beq %2,2f\n" 61 - __ASM__MB 62 55 ".subsection 2\n" 63 56 "2: br 1b\n" 64 57 ".previous" 65 58 : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64) 66 59 : "r" ((long)m), "1" (val) : "memory"); 60 + smp_mb(); 67 61 68 62 return ret; 69 63 } ··· 73 67 { 74 68 unsigned long dummy; 75 69 70 + smp_mb(); 76 71 __asm__ __volatile__( 77 72 "1: ldl_l %0,%4\n" 78 73 " bis $31,%3,%1\n" 79 74 " stl_c %1,%2\n" 80 75 " beq %1,2f\n" 81 - __ASM__MB 82 76 ".subsection 2\n" 83 77 "2: br 1b\n" 84 78 ".previous" 85 79 : "=&r" (val), "=&r" (dummy), "=m" (*m) 86 80 : "rI" (val), "m" (*m) : "memory"); 81 + smp_mb(); 87 82 88 83 return val; 89 84 } ··· 94 87 { 95 88 unsigned long dummy; 96 89 90 + smp_mb(); 97 91 __asm__ __volatile__( 98 92 "1: ldq_l %0,%4\n" 99 93 " bis $31,%3,%1\n" 100 94 " stq_c %1,%2\n" 101 95 " beq %1,2f\n" 102 - __ASM__MB 103 96 ".subsection 2\n" 104 97 "2: br 1b\n" 105 98 ".previous" 106 99 : "=&r" (val), "=&r" (dummy), "=m" (*m) 107 100 : "rI" (val), "m" (*m) : "memory"); 101 + smp_mb(); 108 102 109 103 return val; 110 104 } ··· 136 128 * store NEW in MEM. Return the initial value in MEM. Success is 137 129 * indicated by comparing RETURN with OLD. 138 130 * 139 - * The memory barrier should be placed in SMP only when we actually 140 - * make the change. If we don't change anything (so if the returned 141 - * prev is equal to old) then we aren't acquiring anything new and 142 - * we don't need any memory barrier as far I can tell. 131 + * The leading and the trailing memory barriers guarantee that these 132 + * operations are fully ordered. 133 + * 134 + * The trailing memory barrier is placed in SMP unconditionally, in 135 + * order to guarantee that dependency ordering is preserved when a 136 + * dependency is headed by an unsuccessful operation. 143 137 */ 144 138 145 139 static inline unsigned long ··· 149 139 { 150 140 unsigned long prev, tmp, cmp, addr64; 151 141 142 + smp_mb(); 152 143 __asm__ __volatile__( 153 144 " andnot %5,7,%4\n" 154 145 " insbl %1,%5,%1\n" ··· 161 150 " or %1,%2,%2\n" 162 151 " stq_c %2,0(%4)\n" 163 152 " beq %2,3f\n" 164 - __ASM__MB 165 153 "2:\n" 166 154 ".subsection 2\n" 167 155 "3: br 1b\n" 168 156 ".previous" 169 157 : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64) 170 158 : "r" ((long)m), "Ir" (old), "1" (new) : "memory"); 159 + smp_mb(); 171 160 172 161 return prev; 173 162 } ··· 177 166 { 178 167 unsigned long prev, tmp, cmp, addr64; 179 168 169 + smp_mb(); 180 170 __asm__ __volatile__( 181 171 " andnot %5,7,%4\n" 182 172 " inswl %1,%5,%1\n" ··· 189 177 " or %1,%2,%2\n" 190 178 " stq_c %2,0(%4)\n" 191 179 " beq %2,3f\n" 192 - __ASM__MB 193 180 "2:\n" 194 181 ".subsection 2\n" 195 182 "3: br 1b\n" 196 183 ".previous" 197 184 : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64) 198 185 : "r" ((long)m), "Ir" (old), "1" (new) : "memory"); 186 + smp_mb(); 199 187 200 188 return prev; 201 189 } ··· 205 193 { 206 194 unsigned long prev, cmp; 207 195 196 + smp_mb(); 208 197 __asm__ __volatile__( 209 198 "1: ldl_l %0,%5\n" 210 199 " cmpeq %0,%3,%1\n" ··· 213 200 " mov %4,%1\n" 214 201 " stl_c %1,%2\n" 215 202 " beq %1,3f\n" 216 - __ASM__MB 217 203 "2:\n" 218 204 ".subsection 2\n" 219 205 "3: br 1b\n" 220 206 ".previous" 221 207 : "=&r"(prev), "=&r"(cmp), "=m"(*m) 222 208 : "r"((long) old), "r"(new), "m"(*m) : "memory"); 209 + smp_mb(); 223 210 224 211 return prev; 225 212 } ··· 229 216 { 230 217 unsigned long prev, cmp; 231 218 219 + smp_mb(); 232 220 __asm__ __volatile__( 233 221 "1: ldq_l %0,%5\n" 234 222 " cmpeq %0,%3,%1\n" ··· 237 223 " mov %4,%1\n" 238 224 " stq_c %1,%2\n" 239 225 " beq %1,3f\n" 240 - __ASM__MB 241 226 "2:\n" 242 227 ".subsection 2\n" 243 228 "3: br 1b\n" 244 229 ".previous" 245 230 : "=&r"(prev), "=&r"(cmp), "=m"(*m) 246 231 : "r"((long) old), "r"(new), "m"(*m) : "memory"); 232 + smp_mb(); 247 233 248 234 return prev; 249 235 }
+5
include/linux/mutex.h
··· 66 66 #endif 67 67 }; 68 68 69 + /* 70 + * Internal helper function; C doesn't allow us to hide it :/ 71 + * 72 + * DO NOT USE (outside of mutex code). 73 + */ 69 74 static inline struct task_struct *__mutex_owner(struct mutex *lock) 70 75 { 71 76 return (struct task_struct *)(atomic_long_read(&lock->owner) & ~0x07);