]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
x86/atomic: Fix smp_mb__{before,after}_atomic()
authorPeter Zijlstra <peterz@infradead.org>
Wed, 24 Apr 2019 11:38:23 +0000 (13:38 +0200)
committerIngo Molnar <mingo@kernel.org>
Mon, 17 Jun 2019 10:09:59 +0000 (12:09 +0200)
Recent probing at the Linux Kernel Memory Model uncovered a
'surprise'. Strongly ordered architectures where the atomic RmW
primitive implies full memory ordering and
smp_mb__{before,after}_atomic() are a simple barrier() (such as x86)
fail for:

*x = 1;
atomic_inc(u);
smp_mb__after_atomic();
r0 = *y;

Because, while the atomic_inc() implies memory order, it
(surprisingly) does not provide a compiler barrier. This then allows
the compiler to re-order like so:

atomic_inc(u);
*x = 1;
smp_mb__after_atomic();
r0 = *y;

Which the CPU is then allowed to re-order (under TSO rules) like:

atomic_inc(u);
r0 = *y;
*x = 1;

And this very much was not intended. Therefore strengthen the atomic
RmW ops to include a compiler barrier.

NOTE: atomic_{or,and,xor} and the bitops already had the compiler
barrier.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Documentation/atomic_t.txt
arch/x86/include/asm/atomic.h
arch/x86/include/asm/atomic64_64.h
arch/x86/include/asm/barrier.h

index 89eae7f6b3601612e858688282be6a55770e7b3f..d439a0fdbe4756c8166ea9944829f5efe565ad82 100644 (file)
@@ -196,6 +196,9 @@ These helper barriers exist because architectures have varying implicit
 ordering on their SMP atomic primitives. For example our TSO architectures
 provide full ordered atomics and these barriers are no-ops.
 
+NOTE: when the atomic RmW ops are fully ordered, they should also imply a
+compiler barrier.
+
 Thus:
 
   atomic_fetch_add();
index ea3d95275b43580ff48ed96d1e7376455d20746e..115127c7ad28ab5e8ba6d0732d72032cbef114c8 100644 (file)
@@ -54,7 +54,7 @@ static __always_inline void arch_atomic_add(int i, atomic_t *v)
 {
        asm volatile(LOCK_PREFIX "addl %1,%0"
                     : "+m" (v->counter)
-                    : "ir" (i));
+                    : "ir" (i) : "memory");
 }
 
 /**
@@ -68,7 +68,7 @@ static __always_inline void arch_atomic_sub(int i, atomic_t *v)
 {
        asm volatile(LOCK_PREFIX "subl %1,%0"
                     : "+m" (v->counter)
-                    : "ir" (i));
+                    : "ir" (i) : "memory");
 }
 
 /**
@@ -95,7 +95,7 @@ static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v)
 static __always_inline void arch_atomic_inc(atomic_t *v)
 {
        asm volatile(LOCK_PREFIX "incl %0"
-                    : "+m" (v->counter));
+                    : "+m" (v->counter) :: "memory");
 }
 #define arch_atomic_inc arch_atomic_inc
 
@@ -108,7 +108,7 @@ static __always_inline void arch_atomic_inc(atomic_t *v)
 static __always_inline void arch_atomic_dec(atomic_t *v)
 {
        asm volatile(LOCK_PREFIX "decl %0"
-                    : "+m" (v->counter));
+                    : "+m" (v->counter) :: "memory");
 }
 #define arch_atomic_dec arch_atomic_dec
 
index 703b7dfd45e09ea8eb44a568c60d2af11d5792c1..95c6ceac66b92a0670dd5a6c50e73095868e26b6 100644 (file)
@@ -45,7 +45,7 @@ static __always_inline void arch_atomic64_add(s64 i, atomic64_t *v)
 {
        asm volatile(LOCK_PREFIX "addq %1,%0"
                     : "=m" (v->counter)
-                    : "er" (i), "m" (v->counter));
+                    : "er" (i), "m" (v->counter) : "memory");
 }
 
 /**
@@ -59,7 +59,7 @@ static inline void arch_atomic64_sub(s64 i, atomic64_t *v)
 {
        asm volatile(LOCK_PREFIX "subq %1,%0"
                     : "=m" (v->counter)
-                    : "er" (i), "m" (v->counter));
+                    : "er" (i), "m" (v->counter) : "memory");
 }
 
 /**
@@ -87,7 +87,7 @@ static __always_inline void arch_atomic64_inc(atomic64_t *v)
 {
        asm volatile(LOCK_PREFIX "incq %0"
                     : "=m" (v->counter)
-                    : "m" (v->counter));
+                    : "m" (v->counter) : "memory");
 }
 #define arch_atomic64_inc arch_atomic64_inc
 
@@ -101,7 +101,7 @@ static __always_inline void arch_atomic64_dec(atomic64_t *v)
 {
        asm volatile(LOCK_PREFIX "decq %0"
                     : "=m" (v->counter)
-                    : "m" (v->counter));
+                    : "m" (v->counter) : "memory");
 }
 #define arch_atomic64_dec arch_atomic64_dec
 
index 14de0432d288414bd1437e44b8cb13facc6f12e9..84f848c2541a6e5febb218fc64d209270c80e9bc 100644 (file)
@@ -80,8 +80,8 @@ do {                                                                  \
 })
 
 /* Atomic operations are already serializing on x86 */
-#define __smp_mb__before_atomic()      barrier()
-#define __smp_mb__after_atomic()       barrier()
+#define __smp_mb__before_atomic()      do { } while (0)
+#define __smp_mb__after_atomic()       do { } while (0)
 
 #include <asm-generic/barrier.h>