linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses
@ 2014-11-25 12:38 Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 01/10] KVM: s390: Fix ipte locking Christian Borntraeger
                   ` (10 more replies)
  0 siblings, 11 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

As discussed on LKML http://marc.info/?i=54611D86.4040306%40de.ibm.com
ACCESS_ONCE might fail with specific compiler for non-scalar accesses.

Here is a set of patches to tackle that problem.

The first patch is already in kvm/next and this series is against rc3 (as
kvm/next so that we can avoid a merge conflict as soon as this series
has stabilized).
The 2nd patch introduces READ_ONCE/ASSIGN_ONCE as suggested by Linus.
The 2nd to last patch will force ACCESS_ONCE to error-out if it is used
on non-scalar accesses.

I have cross-compiled the resulting kernel with defconfig for
microblaze, m68k, alpha, s390,x86_64, i686, sparc, sparc64, mips,
ia64, arm and arm64.
Will Deacon pointed me to the right defconfig for arm32 to also trigger
a finding here.
Runtime testing was only done on s390x.

There is a small problem left with sparc (32bit) and m68k:

mm/rmap.c: In function 'mm_find_pmd':
include/linux/compiler.h:220:72: warning: '__val' may be used uninitialized in this function [-Wmaybe-uninitialized]
       ({ typeof(p) __val; __read_once_size(&p, &__val, sizeof(__val)); __val; })
                                                                        ^
include/linux/compiler.h:220:20: note: '__val' was declared here
       ({ typeof(p) __val; __read_once_size(&p, &__val, sizeof(__val)); __val; })
                    ^
mm/rmap.c:584:9: note: in expansion of macro 'READ_ONCE'
  pmde = READ_ONCE(*pmd);

Reason is that for both architectures pmd_t is long[16]. WTF?

So the next spin will either fix m68k/sparc or use a barrier + ACCESS_ONCE.

Comments?

Christian Borntraeger (10):
  KVM: s390: Fix ipte locking
  kernel: Provide READ_ONCE and ASSIGN_ONCE
  mm: replace ACCESS_ONCE with READ_ONCE
  x86/spinlock: Replace ACCESS_ONCE with READ_ONCE/ASSIGN_ONCE
  x86: Replace ACCESS_ONCE in gup with READ_ONCE
  mips: Replace ACCESS_ONCE in gup with READ_ONCE
  arm64: Replace ACCESS_ONCE for spinlock code with READ_ONCE
  arm: Replace ACCESS_ONCE for spinlock code with READ_ONCE
  tighten rules for ACCESS ONCE
  KVM: s390: change ipte lock from barrier to READ_ONCE

 arch/arm/include/asm/spinlock.h   |  4 ++--
 arch/arm64/include/asm/spinlock.h |  4 ++--
 arch/mips/mm/gup.c                |  2 +-
 arch/s390/kvm/gaccess.c           | 14 +++++++------
 arch/x86/include/asm/spinlock.h   |  8 +++----
 arch/x86/mm/gup.c                 |  2 +-
 include/linux/compiler.h          | 44 ++++++++++++++++++++++++++++++++++++++-
 mm/gup.c                          |  2 +-
 mm/memory.c                       |  2 +-
 mm/rmap.c                         |  2 +-
 10 files changed, 64 insertions(+), 20 deletions(-)



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCHv2 01/10] KVM: s390: Fix ipte locking
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 02/10] kernel: Provide READ_ONCE and ASSIGN_ONCE Christian Borntraeger
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger, stable, #, v3.16+

ipte_unlock_siif uses cmpxchg to replace the in-memory data of the ipte
lock together with ACCESS_ONCE for the intial read.

union ipte_control {
        unsigned long val;
        struct {
                unsigned long k  : 1;
                unsigned long kh : 31;
                unsigned long kg : 32;
        };
};
[...]
static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
{
        union ipte_control old, new, *ic;

        ic = &vcpu->kvm->arch.sca->ipte_control;
        do {
                new = old = ACCESS_ONCE(*ic);
                new.kh--;
                if (!new.kh)
                        new.k = 0;
        } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
        if (!new.kh)
                wake_up(&vcpu->kvm->arch.ipte_wq);
}

The new value, is loaded twice from memory with gcc 4.7.2 of
fedora 18, despite the ACCESS_ONCE:

--->

l       %r4,0(%r3)      <--- load first 32 bit of lock (k and kh) in r4
alfi    %r4,2147483647  <--- add -1 to r4
llgtr   %r4,%r4         <--- zero out the sign bit of r4
lg      %r1,0(%r3)      <--- load all 64 bit of lock into new
lgr     %r2,%r1         <--- load the same into old
risbg   %r1,%r4,1,31,32 <--- shift and insert r4 into the bits 1-31 of
new
llihf   %r4,2147483647
ngrk    %r4,%r1,%r4
jne     aa0 <ipte_unlock+0xf8>
nihh    %r1,32767
lgr     %r4,%r2
csg     %r4,%r1,0(%r3)
cgr     %r2,%r4
jne     a70 <ipte_unlock+0xc8>

If the memory value changes between the first load (l) and the second
load (lg) we are broken. If that happens VCPU threads will hang
(unkillable) in handle_ipte_interlock.

Andreas Krebbel analyzed this and tracked it down to a compiler bug in
that version:
"while it is not that obvious the C99 standard basically forbids
duplicating the memory access also in that case. For an argumentation of
a similiar case please see:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278#c43

For the implementation-defined cases regarding volatile there are some
GCC-specific clarifications which can be found here:
https://gcc.gnu.org/onlinedocs/gcc/Volatiles.html#Volatiles

I've tracked down the problem with a reduced testcase. The problem was
that during a tree level optimization (SRA - scalar replacement of
aggregates) the volatile marker is lost. And an RTL level optimizer (CSE
- common subexpression elimination) then propagated the memory read into
  its second use introducing another access to the memory location. So
indeed Christian's suspicion that the union access has something to do
with it is correct (since it triggered the SRA optimization).

This issue has been reported and fixed in the GCC 4.8 development cycle:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145"

This patch replaces the ACCESS_ONCE scheme with a barrier() based scheme
that should work for all supported compilers.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: stable@vger.kernel.org # v3.16+
---
 arch/s390/kvm/gaccess.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 0f961a1..6dc0ad9 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -229,10 +229,12 @@ static void ipte_lock_simple(struct kvm_vcpu *vcpu)
 		goto out;
 	ic = &vcpu->kvm->arch.sca->ipte_control;
 	do {
-		old = ACCESS_ONCE(*ic);
+		old = *ic;
+		barrier();
 		while (old.k) {
 			cond_resched();
-			old = ACCESS_ONCE(*ic);
+			old = *ic;
+			barrier();
 		}
 		new = old;
 		new.k = 1;
@@ -251,7 +253,9 @@ static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
 		goto out;
 	ic = &vcpu->kvm->arch.sca->ipte_control;
 	do {
-		new = old = ACCESS_ONCE(*ic);
+		old = *ic;
+		barrier();
+		new = old;
 		new.k = 0;
 	} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
 	wake_up(&vcpu->kvm->arch.ipte_wq);
@@ -265,10 +269,12 @@ static void ipte_lock_siif(struct kvm_vcpu *vcpu)
 
 	ic = &vcpu->kvm->arch.sca->ipte_control;
 	do {
-		old = ACCESS_ONCE(*ic);
+		old = *ic;
+		barrier();
 		while (old.kg) {
 			cond_resched();
-			old = ACCESS_ONCE(*ic);
+			old = *ic;
+			barrier();
 		}
 		new = old;
 		new.k = 1;
@@ -282,7 +288,9 @@ static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
 
 	ic = &vcpu->kvm->arch.sca->ipte_control;
 	do {
-		new = old = ACCESS_ONCE(*ic);
+		old = *ic;
+		barrier();
+		new = old;
 		new.kh--;
 		if (!new.kh)
 			new.k = 0;
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 02/10] kernel: Provide READ_ONCE and ASSIGN_ONCE
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 01/10] KVM: s390: Fix ipte locking Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-25 15:59   ` Paul E. McKenney
  2014-11-25 12:38 ` [PATCHv2 03/10] mm: replace ACCESS_ONCE with READ_ONCE Christian Borntraeger
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

ACCESS_ONCE does not work reliably on non-scalar types. For
example gcc 4.6 and 4.7 might remove the volatile tag for such
accesses during the SRA (scalar replacement of aggregates) step
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)

Let's provide READ_ONCE/ASSIGN_ONCE that will do all accesses via
scalar types.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 include/linux/compiler.h | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index d5ad7b1..0ff01f2 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -186,6 +186,40 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
 # define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
 #endif
 
+#include <linux/types.h>
+
+static __always_inline void __assign_once_size(volatile void *p, void *res, int size)
+{
+	switch (size) {
+	case 1: *(volatile u8 *)p = *(u8 *)res; break;
+	case 2: *(volatile u16 *)p = *(u16 *)res; break;
+	case 4: *(volatile u32 *)p = *(u32 *)res; break;
+#ifdef CONFIG_64BIT
+	case 8: *(volatile u64 *)p = *(u64 *)res; break;
+#endif
+       }
+}
+
+#define ASSIGN_ONCE(val, p) \
+      ({ typeof(p) __val; __val = val; __assign_once_size(&p, &__val, sizeof(__val)); __val; })
+
+
+static __always_inline void __read_once_size(volatile void *p, void *res, int size)
+{
+	switch (size) {
+	case 1: *(u8 *)res = *(volatile u8 *)p; break;
+	case 2: *(u16 *)res = *(volatile u16 *)p; break;
+	case 4: *(u32 *)res = *(volatile u32 *)p; break;
+#ifdef CONFIG_64BIT
+	case 8: *(u64 *)res = *(volatile u64 *)p; break;
+#endif
+       }
+}
+
+#define READ_ONCE(p) \
+      ({ typeof(p) __val; __read_once_size(&p, &__val, sizeof(__val)); __val; })
+
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 03/10] mm: replace ACCESS_ONCE with READ_ONCE
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 01/10] KVM: s390: Fix ipte locking Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 02/10] kernel: Provide READ_ONCE and ASSIGN_ONCE Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 04/10] x86/spinlock: Replace ACCESS_ONCE with READ_ONCE/ASSIGN_ONCE Christian Borntraeger
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

ACCESS_ONCE does not work reliably on non-scalar types. For
example gcc 4.6 and 4.7 might remove the volatile tag for such
accesses during the SRA (scalar replacement of aggregates) step
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)

Let's change the code to access the page table elements with
READ_ONCE that does implicit scalar accesses.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 mm/gup.c    | 2 +-
 mm/memory.c | 2 +-
 mm/rmap.c   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/mm/gup.c b/mm/gup.c
index cd62c8c..f2305de 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -917,7 +917,7 @@ static int gup_pud_range(pgd_t *pgdp, unsigned long addr, unsigned long end,
 
 	pudp = pud_offset(pgdp, addr);
 	do {
-		pud_t pud = ACCESS_ONCE(*pudp);
+		pud_t pud = READ_ONCE(*pudp);
 
 		next = pud_addr_end(addr, end);
 		if (pud_none(pud))
diff --git a/mm/memory.c b/mm/memory.c
index 3e50383..9e0c84e 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3202,7 +3202,7 @@ static int handle_pte_fault(struct mm_struct *mm,
 	pte_t entry;
 	spinlock_t *ptl;
 
-	entry = ACCESS_ONCE(*pte);
+	entry = READ_ONCE(*pte);
 	if (!pte_present(entry)) {
 		if (pte_none(entry)) {
 			if (vma->vm_ops) {
diff --git a/mm/rmap.c b/mm/rmap.c
index 19886fb..3152a9c 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -581,7 +581,7 @@ pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address)
 	 * without holding anon_vma lock for write.  So when looking for a
 	 * genuine pmde (in which to find pte), test present and !THP together.
 	 */
-	pmde = ACCESS_ONCE(*pmd);
+	pmde = READ_ONCE(*pmd);
 	if (!pmd_present(pmde) || pmd_trans_huge(pmde))
 		pmd = NULL;
 out:
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 04/10] x86/spinlock: Replace ACCESS_ONCE with READ_ONCE/ASSIGN_ONCE
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
                   ` (2 preceding siblings ...)
  2014-11-25 12:38 ` [PATCHv2 03/10] mm: replace ACCESS_ONCE with READ_ONCE Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-25 20:29   ` Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 05/10] x86: Replace ACCESS_ONCE in gup with READ_ONCE Christian Borntraeger
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

ACCESS_ONCE does not work reliably on non-scalar types. For
example gcc 4.6 and 4.7 might remove the volatile tag for such
accesses during the SRA (scalar replacement of aggregates) step
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)

Change the spinlock code to replace ACCESS_ONCE with READ_ONCE
and ASSIGN_ONCE.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 arch/x86/include/asm/spinlock.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 9295016..af6e673 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -92,7 +92,7 @@ static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
 		unsigned count = SPIN_THRESHOLD;
 
 		do {
-			if (ACCESS_ONCE(lock->tickets.head) == inc.tail)
+			if (ASSIGN_ONCE(inc.tail, lock->tickets.head))
 				goto out;
 			cpu_relax();
 		} while (--count);
@@ -105,7 +105,7 @@ static __always_inline int arch_spin_trylock(arch_spinlock_t *lock)
 {
 	arch_spinlock_t old, new;
 
-	old.tickets = ACCESS_ONCE(lock->tickets);
+	old.tickets = READ_ONCE(lock->tickets);
 	if (old.tickets.head != (old.tickets.tail & ~TICKET_SLOWPATH_FLAG))
 		return 0;
 
@@ -162,14 +162,14 @@ static __always_inline void arch_spin_unlock(arch_spinlock_t *lock)
 
 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 {
-	struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets);
+	struct __raw_tickets tmp = READ_ONCE(lock->tickets);
 
 	return tmp.tail != tmp.head;
 }
 
 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
 {
-	struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets);
+	struct __raw_tickets tmp = READ_ONCE(lock->tickets);
 
 	return (__ticket_t)(tmp.tail - tmp.head) > TICKET_LOCK_INC;
 }
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 05/10] x86: Replace ACCESS_ONCE in gup with READ_ONCE
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
                   ` (3 preceding siblings ...)
  2014-11-25 12:38 ` [PATCHv2 04/10] x86/spinlock: Replace ACCESS_ONCE with READ_ONCE/ASSIGN_ONCE Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 06/10] mips: " Christian Borntraeger
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

ACCESS_ONCE does not work reliably on non-scalar types. For
example gcc 4.6 and 4.7 might remove the volatile tag for such
accesses during the SRA (scalar replacement of aggregates) step
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)

Change the gup code to replace ACCESS_ONCE with READ_ONCE.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 arch/x86/mm/gup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c
index 207d9aef..d754782 100644
--- a/arch/x86/mm/gup.c
+++ b/arch/x86/mm/gup.c
@@ -15,7 +15,7 @@
 static inline pte_t gup_get_pte(pte_t *ptep)
 {
 #ifndef CONFIG_X86_PAE
-	return ACCESS_ONCE(*ptep);
+	return READ_ONCE(*ptep);
 #else
 	/*
 	 * With get_user_pages_fast, we walk down the pagetables without taking
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 06/10] mips: Replace ACCESS_ONCE in gup with READ_ONCE
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
                   ` (4 preceding siblings ...)
  2014-11-25 12:38 ` [PATCHv2 05/10] x86: Replace ACCESS_ONCE in gup with READ_ONCE Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 07/10] arm64: Replace ACCESS_ONCE for spinlock code " Christian Borntraeger
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

ACCESS_ONCE does not work reliably on non-scalar types. For
example gcc 4.6 and 4.7 might remove the volatile tag for such
accesses during the SRA (scalar replacement of aggregates) step
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)

Change the gup code to replace ACCESS_ONCE with READ_ONCE.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 arch/mips/mm/gup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c
index 06ce17c..8aa50e3 100644
--- a/arch/mips/mm/gup.c
+++ b/arch/mips/mm/gup.c
@@ -30,7 +30,7 @@ retry:
 
 	return pte;
 #else
-	return ACCESS_ONCE(*ptep);
+	return READ_ONCE(*ptep);
 #endif
 }
 
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 07/10] arm64: Replace ACCESS_ONCE for spinlock code with READ_ONCE
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
                   ` (5 preceding siblings ...)
  2014-11-25 12:38 ` [PATCHv2 06/10] mips: " Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 08/10] arm: " Christian Borntraeger
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

ACCESS_ONCE does not work reliably on non-scalar types. For
example gcc 4.6 and 4.7 might remove the volatile tag for such
accesses during the SRA (scalar replacement of aggregates) step
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)

Change the spinlock code to replace ACCESS_ONCE with READ_ONCE.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 arch/arm64/include/asm/spinlock.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
index c45b7b1..cee1287 100644
--- a/arch/arm64/include/asm/spinlock.h
+++ b/arch/arm64/include/asm/spinlock.h
@@ -99,12 +99,12 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 {
-	return !arch_spin_value_unlocked(ACCESS_ONCE(*lock));
+	return !arch_spin_value_unlocked(READ_ONCE(*lock));
 }
 
 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
 {
-	arch_spinlock_t lockval = ACCESS_ONCE(*lock);
+	arch_spinlock_t lockval = READ_ONCE(*lock);
 	return (lockval.next - lockval.owner) > 1;
 }
 #define arch_spin_is_contended	arch_spin_is_contended
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 08/10] arm: Replace ACCESS_ONCE for spinlock code with READ_ONCE
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
                   ` (6 preceding siblings ...)
  2014-11-25 12:38 ` [PATCHv2 07/10] arm64: Replace ACCESS_ONCE for spinlock code " Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 09/10] tighten rules for ACCESS ONCE Christian Borntraeger
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

ACCESS_ONCE does not work reliably on non-scalar types. For
example gcc 4.6 and 4.7 might remove the volatile tag for such
accesses during the SRA (scalar replacement of aggregates) step
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)

Change the spinlock code to replace ACCESS_ONCE with READ_ONCE.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 arch/arm/include/asm/spinlock.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index ac4bfae..0fa4184 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -120,12 +120,12 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 {
-	return !arch_spin_value_unlocked(ACCESS_ONCE(*lock));
+	return !arch_spin_value_unlocked(READ_ONCE(*lock));
 }
 
 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
 {
-	struct __raw_tickets tickets = ACCESS_ONCE(lock->tickets);
+	struct __raw_tickets tickets = READ_ONCE(lock->tickets);
 	return (tickets.next - tickets.owner) > 1;
 }
 #define arch_spin_is_contended	arch_spin_is_contended
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 09/10] tighten rules for ACCESS ONCE
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
                   ` (7 preceding siblings ...)
  2014-11-25 12:38 ` [PATCHv2 08/10] arm: " Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-25 12:38 ` [PATCHv2 10/10] KVM: s390: change ipte lock from barrier to READ_ONCE Christian Borntraeger
  2014-11-26 19:20 ` [PATCHv3 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
  10 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

Now that all non-scalar users of ACCESS_ONCE have been converted
to READ_ONCE or ASSIGN once, lets tighten ACCESS_ONCE to only
work on scalar types.
This variant was proposed by Alexei Starovoitov.

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 include/linux/compiler.h | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 0ff01f2..7265a6c 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -411,8 +411,16 @@ static __always_inline void __read_once_size(volatile void *p, void *res, int si
  * merging, or refetching absolutely anything at any time.  Its main intended
  * use is to mediate communication between process-level code and irq/NMI
  * handlers, all running on the same CPU.
+ *
+ * ACCESS_ONCE will only work on scalar types. For union types, ACCESS_ONCE
+ * on a union member will work as long as the size of the member matches the
+ * size of the union and the size is smaller than word size.
+ * If possible READ_ONCE/ASSIGN_ONCE should be used instead.
  */
-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+#define __ACCESS_ONCE(x) ({ \
+	 __maybe_unused typeof(x) __var = 0; \
+	(volatile typeof(x) *)&(x); })
+#define ACCESS_ONCE(x) (*__ACCESS_ONCE(x))
 
 /* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */
 #ifdef CONFIG_KPROBES
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 10/10] KVM: s390: change ipte lock from barrier to READ_ONCE
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
                   ` (8 preceding siblings ...)
  2014-11-25 12:38 ` [PATCHv2 09/10] tighten rules for ACCESS ONCE Christian Borntraeger
@ 2014-11-25 12:38 ` Christian Borntraeger
  2014-11-26 19:20 ` [PATCHv3 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
  10 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 12:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch@vger.kernel.org, linux-mips@linux-mips.org,
	linux-x86_64@vger.kernel.org, linux-s390, Paolo Bonzini, paulmck,
	mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King,
	Christian Borntraeger

Now that we have the READ_ONCE solution, we can change the ipte lock
from a barrier solution to READ_ONCE. The barrier and the explanation
of the bug was introduced in commit 1365039d0cb3 ("KVM: s390: Fix
ipte locking")

Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 arch/s390/kvm/gaccess.c | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 6dc0ad9..8f195fa 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -229,12 +229,10 @@ static void ipte_lock_simple(struct kvm_vcpu *vcpu)
 		goto out;
 	ic = &vcpu->kvm->arch.sca->ipte_control;
 	do {
-		old = *ic;
-		barrier();
+		old = READ_ONCE(*ic);
 		while (old.k) {
 			cond_resched();
-			old = *ic;
-			barrier();
+			old = READ_ONCE(*ic);
 		}
 		new = old;
 		new.k = 1;
@@ -253,8 +251,7 @@ static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
 		goto out;
 	ic = &vcpu->kvm->arch.sca->ipte_control;
 	do {
-		old = *ic;
-		barrier();
+		old = READ_ONCE(*ic);
 		new = old;
 		new.k = 0;
 	} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
@@ -269,12 +266,10 @@ static void ipte_lock_siif(struct kvm_vcpu *vcpu)
 
 	ic = &vcpu->kvm->arch.sca->ipte_control;
 	do {
-		old = *ic;
-		barrier();
+		old = READ_ONCE(*ic);
 		while (old.kg) {
 			cond_resched();
-			old = *ic;
-			barrier();
+			old = READ_ONCE(*ic);
 		}
 		new = old;
 		new.k = 1;
@@ -288,8 +283,7 @@ static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
 
 	ic = &vcpu->kvm->arch.sca->ipte_control;
 	do {
-		old = *ic;
-		barrier();
+		old = READ_ONCE(*ic);
 		new = old;
 		new.kh--;
 		if (!new.kh)
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 02/10] kernel: Provide READ_ONCE and ASSIGN_ONCE
  2014-11-25 12:38 ` [PATCHv2 02/10] kernel: Provide READ_ONCE and ASSIGN_ONCE Christian Borntraeger
@ 2014-11-25 15:59   ` Paul E. McKenney
  2014-11-25 17:28     ` Linus Torvalds
  2014-11-25 19:35     ` Christian Borntraeger
  0 siblings, 2 replies; 17+ messages in thread
From: Paul E. McKenney @ 2014-11-25 15:59 UTC (permalink / raw)
  To: Christian Borntraeger
  Cc: linux-kernel, linux-arch, Paolo Bonzini, mingo, torvalds,
	Catalin Marinas, Will Deacon, Alexei Starovoitov, David Howells,
	Russell King

On Tue, Nov 25, 2014 at 01:38:29PM +0100, Christian Borntraeger wrote:
> ACCESS_ONCE does not work reliably on non-scalar types. For
> example gcc 4.6 and 4.7 might remove the volatile tag for such
> accesses during the SRA (scalar replacement of aggregates) step
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)
> 
> Let's provide READ_ONCE/ASSIGN_ONCE that will do all accesses via
> scalar types.
> 
> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
> ---
>  include/linux/compiler.h | 34 ++++++++++++++++++++++++++++++++++
>  1 file changed, 34 insertions(+)
> 
> diff --git a/include/linux/compiler.h b/include/linux/compiler.h
> index d5ad7b1..0ff01f2 100644
> --- a/include/linux/compiler.h
> +++ b/include/linux/compiler.h
> @@ -186,6 +186,40 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
>  # define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
>  #endif
> 
> +#include <linux/types.h>
> +
> +static __always_inline void __assign_once_size(volatile void *p, void *res, int size)
> +{
> +	switch (size) {
> +	case 1: *(volatile u8 *)p = *(u8 *)res; break;
> +	case 2: *(volatile u16 *)p = *(u16 *)res; break;
> +	case 4: *(volatile u32 *)p = *(u32 *)res; break;
> +#ifdef CONFIG_64BIT
> +	case 8: *(volatile u64 *)p = *(u64 *)res; break;

We really need something like this to catch invalid sizes:

	default: invoke_nonexistent_function();

Of course, a BUILD_BUG_ON() would give a nicer error message.

Without this, in my testing, the following compiles without error, generating
no code:

	struct foo {
		int field[10];
	} f, f1;

	f1 = READ_ONCE(f);

There is probably some better way to do this.

> +#endif
> +       }
> +}
> +
> +#define ASSIGN_ONCE(val, p) \
> +      ({ typeof(p) __val; __val = val; __assign_once_size(&p, &__val, sizeof(__val)); __val; })
> +
> +
> +static __always_inline void __read_once_size(volatile void *p, void *res, int size)
> +{
> +	switch (size) {
> +	case 1: *(u8 *)res = *(volatile u8 *)p; break;
> +	case 2: *(u16 *)res = *(volatile u16 *)p; break;
> +	case 4: *(u32 *)res = *(volatile u32 *)p; break;
> +#ifdef CONFIG_64BIT
> +	case 8: *(u64 *)res = *(volatile u64 *)p; break;
> +#endif

Ditto here.

							Thanx, Paul

> +       }
> +}
> +
> +#define READ_ONCE(p) \
> +      ({ typeof(p) __val; __read_once_size(&p, &__val, sizeof(__val)); __val; })
> +
> +
>  #endif /* __KERNEL__ */
> 
>  #endif /* __ASSEMBLY__ */
> -- 
> 1.9.3
> 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 02/10] kernel: Provide READ_ONCE and ASSIGN_ONCE
  2014-11-25 15:59   ` Paul E. McKenney
@ 2014-11-25 17:28     ` Linus Torvalds
  2014-11-25 17:50       ` Paul E. McKenney
  2014-11-25 19:35     ` Christian Borntraeger
  1 sibling, 1 reply; 17+ messages in thread
From: Linus Torvalds @ 2014-11-25 17:28 UTC (permalink / raw)
  To: Paul McKenney
  Cc: Christian Borntraeger, Linux Kernel Mailing List, linux-arch,
	Paolo Bonzini, Ingo Molnar, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King

On Tue, Nov 25, 2014 at 7:59 AM, Paul E. McKenney
<paulmck@linux.vnet.ibm.com> wrote:
>
> We really need something like this to catch invalid sizes:
>
>         default: invoke_nonexistent_function();

Actually, I wonder if we should make the default: case actually just
do something like

   barrier();
   memcpy(res, p, size);
   barrier();

which in no way guarantees that it's an _atomic_ access, but it does
guarantee the semantics that you get one particular value and it won't
get reloaded later..

That would solve the crazy sparc pte issue too.


               Linus

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 02/10] kernel: Provide READ_ONCE and ASSIGN_ONCE
  2014-11-25 17:28     ` Linus Torvalds
@ 2014-11-25 17:50       ` Paul E. McKenney
  0 siblings, 0 replies; 17+ messages in thread
From: Paul E. McKenney @ 2014-11-25 17:50 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Borntraeger, Linux Kernel Mailing List, linux-arch,
	Paolo Bonzini, Ingo Molnar, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King

On Tue, Nov 25, 2014 at 09:28:33AM -0800, Linus Torvalds wrote:
> On Tue, Nov 25, 2014 at 7:59 AM, Paul E. McKenney
> <paulmck@linux.vnet.ibm.com> wrote:
> >
> > We really need something like this to catch invalid sizes:
> >
> >         default: invoke_nonexistent_function();
> 
> Actually, I wonder if we should make the default: case actually just
> do something like
> 
>    barrier();
>    memcpy(res, p, size);
>    barrier();
> 
> which in no way guarantees that it's an _atomic_ access, but it does
> guarantee the semantics that you get one particular value and it won't
> get reloaded later..
> 
> That would solve the crazy sparc pte issue too.

I would be really worried about confusion due to load/store tearing,
where a READ_ONCE() reads part of its value from one ASSIGN_ONCE()
and the other part from some other ASSIGN_ONCE().  Don't get me wrong,
there are cases where the load/store tearing is harmless, it is just
that in my experience that these cases are anything but the common case.

That said, I do not claim to be familiar with more than a microscopic
fraction of the Linux kernel.

Of course, one way to resolve this would be to have one variant that did
the memcpy() and another that threw a build error, maybe READ_ONCE_FORCE()
and ASSIGN_ONCE_FORC() or some such.  I would -really- like to be informed
if I do READ_ONCE() of a long long on a 32-bit system.  ;-)

/me goes off to see if there are any ACCESS_ONCE() of long longs in RCU...

							Thanx, Paul


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 02/10] kernel: Provide READ_ONCE and ASSIGN_ONCE
  2014-11-25 15:59   ` Paul E. McKenney
  2014-11-25 17:28     ` Linus Torvalds
@ 2014-11-25 19:35     ` Christian Borntraeger
  1 sibling, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 19:35 UTC (permalink / raw)
  To: paulmck
  Cc: linux-kernel, linux-arch, Paolo Bonzini, mingo, torvalds,
	Catalin Marinas, Will Deacon, Alexei Starovoitov, David Howells,
	Russell King

Am 25.11.2014 um 16:59 schrieb Paul E. McKenney:
> On Tue, Nov 25, 2014 at 01:38:29PM +0100, Christian Borntraeger wrote:
>> ACCESS_ONCE does not work reliably on non-scalar types. For
>> example gcc 4.6 and 4.7 might remove the volatile tag for such
>> accesses during the SRA (scalar replacement of aggregates) step
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)
>>
>> Let's provide READ_ONCE/ASSIGN_ONCE that will do all accesses via
>> scalar types.
>>
>> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
>> ---
>>  include/linux/compiler.h | 34 ++++++++++++++++++++++++++++++++++
>>  1 file changed, 34 insertions(+)
>>
>> diff --git a/include/linux/compiler.h b/include/linux/compiler.h
>> index d5ad7b1..0ff01f2 100644
>> --- a/include/linux/compiler.h
>> +++ b/include/linux/compiler.h
>> @@ -186,6 +186,40 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
>>  # define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
>>  #endif
>>
>> +#include <linux/types.h>
>> +
>> +static __always_inline void __assign_once_size(volatile void *p, void *res, int size)
>> +{
>> +	switch (size) {
>> +	case 1: *(volatile u8 *)p = *(u8 *)res; break;
>> +	case 2: *(volatile u16 *)p = *(u16 *)res; break;
>> +	case 4: *(volatile u32 *)p = *(u32 *)res; break;
>> +#ifdef CONFIG_64BIT
>> +	case 8: *(volatile u64 *)p = *(u64 *)res; break;
> 
> We really need something like this to catch invalid sizes:
> 
> 	default: invoke_nonexistent_function();
> 
> Of course, a BUILD_BUG_ON() would give a nicer error message.
> 
> Without this, in my testing, the following compiles without error, generating
> no code:
> 
> 	struct foo {
> 		int field[10];
> 	} f, f1;
> 
> 	f1 = READ_ONCE(f);
> 
> There is probably some better way to do this.

Yes, I was trying to do something for default, but we are in compiler.h and BUILD_BUG_ON etc are not defined. including other header files gave me some trouble, but doing it only inside the ifdef !assembly might work out (as I did with linux/types.h). 

The thing is this case was actually detected see the pmd_t compile error for m68k and sparc. Defining an extern function named read_once_called_for_large_object and then let the linker do the real work might work out as well.



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 04/10] x86/spinlock: Replace ACCESS_ONCE with READ_ONCE/ASSIGN_ONCE
  2014-11-25 12:38 ` [PATCHv2 04/10] x86/spinlock: Replace ACCESS_ONCE with READ_ONCE/ASSIGN_ONCE Christian Borntraeger
@ 2014-11-25 20:29   ` Christian Borntraeger
  0 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-25 20:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch, linux-mips, linux-x86_64, linux-s390, Paolo Bonzini,
	paulmck, mingo, torvalds, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King

Am 25.11.2014 um 13:38 schrieb Christian Borntraeger:
> ACCESS_ONCE does not work reliably on non-scalar types. For
> example gcc 4.6 and 4.7 might remove the volatile tag for such
> accesses during the SRA (scalar replacement of aggregates) step
> (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145)
> 
> Change the spinlock code to replace ACCESS_ONCE with READ_ONCE
> and ASSIGN_ONCE.
> 
> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
> ---
>  arch/x86/include/asm/spinlock.h | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
> index 9295016..af6e673 100644
> --- a/arch/x86/include/asm/spinlock.h
> +++ b/arch/x86/include/asm/spinlock.h
> @@ -92,7 +92,7 @@ static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
>  		unsigned count = SPIN_THRESHOLD;
> 
>  		do {
> -			if (ACCESS_ONCE(lock->tickets.head) == inc.tail)
> +			if (ASSIGN_ONCE(inc.tail, lock->tickets.head))

As Mike pointed out: this should be 
			if (READ_ONCE(lock->tickets.head) == inc.tail)
of course.



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCHv3 00/10] ACCESS_ONCE and non-scalar accesses
  2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
                   ` (9 preceding siblings ...)
  2014-11-25 12:38 ` [PATCHv2 10/10] KVM: s390: change ipte lock from barrier to READ_ONCE Christian Borntraeger
@ 2014-11-26 19:20 ` Christian Borntraeger
  10 siblings, 0 replies; 17+ messages in thread
From: Christian Borntraeger @ 2014-11-26 19:20 UTC (permalink / raw)
  To: torvalds
  Cc: linux-kernel, linux-arch, linux-mips, linux-x86_64, linux-s390,
	Paolo Bonzini, paulmck, mingo, Catalin Marinas, Will Deacon,
	Alexei Starovoitov, David Howells, Russell King

Linus, 

I have changed the code as below (diff to v2). m68k and sparc do compile now. I changed the rmap.c code to use a barrier as the requirement of the code should be trivial. I also use a linker error for the default case. (rmap.c was the only case, so it might be easier to just fix the callers. Furthermore, memcpy did not work that well in compiler.h....) Below is git request pull output if somebody wants to look at the tree. How to proceed? Shall we add this to linux-next and merge in the next cycle if there are no issues? Send around another bunch of patches?

Christian

--------------------------------- snip----------------------
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index af6e673..12a69b4 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -92,7 +92,7 @@ static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
 		unsigned count = SPIN_THRESHOLD;
 
 		do {
-			if (ASSIGN_ONCE(inc.tail, lock->tickets.head))
+			if (READ_ONCE(lock->tickets.head) == inc.tail)
 				goto out;
 			cpu_relax();
 		} while (--count);
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 7265a6c..4434255 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -188,6 +188,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
 
 #include <linux/types.h>
 
+extern void invalid_size_for_ASSIGN_ONCE(void);
 static __always_inline void __assign_once_size(volatile void *p, void *res, int size)
 {
 	switch (size) {
@@ -197,13 +198,14 @@ static __always_inline void __assign_once_size(volatile void *p, void *res, int
 #ifdef CONFIG_64BIT
 	case 8: *(volatile u64 *)p = *(u64 *)res; break;
 #endif
+	default: invalid_size_for_ASSIGN_ONCE();
 	}
 }
 
 #define ASSIGN_ONCE(val, p) \
       ({ typeof(p) __val; __val = val; __assign_once_size(&p, &__val, sizeof(__val)); __val; })
 
-
+extern void invalid_size_for_READ_ONCE(void);
 static __always_inline void __read_once_size(volatile void *p, void *res, int size)
 {
 	switch (size) {
@@ -213,6 +215,7 @@ static __always_inline void __read_once_size(volatile void *p, void *res, int si
 #ifdef CONFIG_64BIT
 	case 8: *(u64 *)res = *(volatile u64 *)p; break;
 #endif
+	default: invalid_size_for_READ_ONCE();
 	}
 }
 
diff --git a/mm/rmap.c b/mm/rmap.c
index 3152a9c..1e54274 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -581,7 +581,8 @@ pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address)
 	 * without holding anon_vma lock for write.  So when looking for a
 	 * genuine pmde (in which to find pte), test present and !THP together.
 	 */
-	pmde = READ_ONCE(*pmd);
+	pmde = *pmd;
+	barrier();
 	if (!pmd_present(pmde) || pmd_trans_huge(pmde))
 		pmd = NULL;
 out:

--------------------------------- snip----------------------



The following changes since commit 0df1f2487d2f0d04703f142813d53615d62a1da4:

  Linux 3.18-rc3 (2014-11-02 15:01:51 -0800)

are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/borntraeger/linux.git tags/access_once

for you to fetch changes up to fbb7eba5b777691dd1f0e106433b78de588ed16e:

  KVM: s390: change ipte lock from barrier to READ_ONCE (2014-11-26 12:30:10 +0100)

----------------------------------------------------------------
As discussed on LKML http://marc.info/?i=54611D86.4040306%40de.ibm.com
ACCESS_ONCE might fail with specific compiler for non-scalar accesses.

Here is a set of patches to tackle that problem.

We first introduce READ_ONCE/ASSIGN_ONCE as suggested by Linus. These
wrappers will make all accesses via scalar wrappers and will also check
that accesses are <= the word size of the system.
The next changes will modify current users of ACCESS_ONCE on non-scalar
types to use READ_ONCE/ASSIGN_ONCE or barrier where necessary.
The 2nd to last patch will force ACCESS_ONCE to error-out if it is used
on non-scalar accesses.

The series is cross-compiled the resulting kernel with defconfig for
microblaze, m68k, alpha, s390,x86_64, i686, sparc, sparc64, mips,
ia64, arm and arm64.

----------------------------------------------------------------
Christian Borntraeger (10):
      KVM: s390: Fix ipte locking
      kernel: Provide READ_ONCE and ASSIGN_ONCE
      mm: replace ACCESS_ONCE with READ_ONCE or barriers
      x86/spinlock: Replace ACCESS_ONCE with READ_ONCE
      x86: Replace ACCESS_ONCE in gup with READ_ONCE
      mips: Replace ACCESS_ONCE in gup with READ_ONCE
      arm64: Replace ACCESS_ONCE for spinlock code with READ_ONCE
      arm: Replace ACCESS_ONCE for spinlock code with READ_ONCE
      tighten rules for ACCESS ONCE
      KVM: s390: change ipte lock from barrier to READ_ONCE

 arch/arm/include/asm/spinlock.h   |  4 ++--
 arch/arm64/include/asm/spinlock.h |  4 ++--
 arch/mips/mm/gup.c                |  2 +-
 arch/s390/kvm/gaccess.c           | 14 ++++++++------
 arch/x86/include/asm/spinlock.h   |  8 ++++----
 arch/x86/mm/gup.c                 |  2 +-
 include/linux/compiler.h          | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 mm/gup.c                          |  2 +-
 mm/memory.c                       |  2 +-
 mm/rmap.c                         |  3 ++-
 10 files changed, 67 insertions(+), 20 deletions(-)





^ permalink raw reply related	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2014-11-26 19:20 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-25 12:38 [PATCHv2 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 01/10] KVM: s390: Fix ipte locking Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 02/10] kernel: Provide READ_ONCE and ASSIGN_ONCE Christian Borntraeger
2014-11-25 15:59   ` Paul E. McKenney
2014-11-25 17:28     ` Linus Torvalds
2014-11-25 17:50       ` Paul E. McKenney
2014-11-25 19:35     ` Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 03/10] mm: replace ACCESS_ONCE with READ_ONCE Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 04/10] x86/spinlock: Replace ACCESS_ONCE with READ_ONCE/ASSIGN_ONCE Christian Borntraeger
2014-11-25 20:29   ` Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 05/10] x86: Replace ACCESS_ONCE in gup with READ_ONCE Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 06/10] mips: " Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 07/10] arm64: Replace ACCESS_ONCE for spinlock code " Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 08/10] arm: " Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 09/10] tighten rules for ACCESS ONCE Christian Borntraeger
2014-11-25 12:38 ` [PATCHv2 10/10] KVM: s390: change ipte lock from barrier to READ_ONCE Christian Borntraeger
2014-11-26 19:20 ` [PATCHv3 00/10] ACCESS_ONCE and non-scalar accesses Christian Borntraeger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).