linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH] lib: Introduce generic __cmpxchg_u64() and use it where needed
@ 2018-10-31 19:52 Guenter Roeck
  2018-10-31 21:32 ` Paul Burton
  0 siblings, 1 reply; 34+ messages in thread
From: Guenter Roeck @ 2018-10-31 19:52 UTC (permalink / raw)
  To: Ralf Baechle, Paul Burton, James Hogan, Benjamin Herrenschmidt,
	Paul Mackerras, Michael Ellerman
  Cc: linux-mips, linux-kernel, linuxppc-dev, Andrew Morton,
	Guenter Roeck, Arnd Bergmann, Trond Myklebust

Some architectures do not or not always support cmpxchg64(). This results
in on/off problems when the function is used in common code. The latest
example is

net/sunrpc/auth_gss/gss_krb5_seal.c: In function 'gss_seq_send64_fetch_and_inc':
net/sunrpc/auth_gss/gss_krb5_seal.c:145:14: error:
	implicit declaration of function 'cmpxchg64'

which is seen with some powerpc and mips builds.

Introduce a generic version of __cmpxchg_u64() and use it for affected
architectures.

Fixes: 21924765862a
	("SUNRPC: use cmpxchg64() in gss_seq_send64_fetch_and_inc()")
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
Couple of questions:
- Is this the right (or an acceptable) approach to fix the problem ?
- Should I split the patch into three, one to introduce __cmpxchg_u64()
  and one per architecture ?
- Who should take the patch (series) ?

 arch/mips/Kconfig                  |  1 +
 arch/mips/include/asm/cmpxchg.h    |  3 ++
 arch/powerpc/Kconfig               |  1 +
 arch/powerpc/include/asm/cmpxchg.h |  3 ++
 lib/Kconfig                        |  3 ++
 lib/Makefile                       |  2 ++
 lib/cmpxchg64.c                    | 60 ++++++++++++++++++++++++++++++++++++++
 7 files changed, 73 insertions(+)
 create mode 100644 lib/cmpxchg64.c

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 80778b40f8fa..7392a5f4e517 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -18,6 +18,7 @@ config MIPS
 	select CPU_PM if CPU_IDLE
 	select DMA_DIRECT_OPS
 	select GENERIC_ATOMIC64 if !64BIT
+	select GENERIC_CMPXCHG64 if !64BIT && SMP
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_CMOS_UPDATE
 	select GENERIC_CPU_AUTOPROBE
diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h
index 89e9fb7976fe..ca837b05bf3d 100644
--- a/arch/mips/include/asm/cmpxchg.h
+++ b/arch/mips/include/asm/cmpxchg.h
@@ -206,6 +206,9 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 #ifndef CONFIG_SMP
 #define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n))
+#else
+extern u64 __cmpxchg_u64(u64 *p, u64 old, u64 new);
+#define cmpxchg64(ptr, o, n) __cmpxchg_u64((ptr), (o), (n))
 #endif
 #endif
 
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index e84943d24e5c..bd1d99c664c4 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -161,6 +161,7 @@ config PPC
 	select EDAC_ATOMIC_SCRUB
 	select EDAC_SUPPORT
 	select GENERIC_ATOMIC64			if PPC32
+	select GENERIC_CMPXCHG64		if PPC32
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_CLOCKEVENTS_BROADCAST	if SMP
 	select GENERIC_CMOS_UPDATE
diff --git a/arch/powerpc/include/asm/cmpxchg.h b/arch/powerpc/include/asm/cmpxchg.h
index 27183871eb3b..da8be4189731 100644
--- a/arch/powerpc/include/asm/cmpxchg.h
+++ b/arch/powerpc/include/asm/cmpxchg.h
@@ -534,8 +534,11 @@ __cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
 	cmpxchg_acquire((ptr), (o), (n));				\
 })
 #else
+extern u64 __cmpxchg_u64(u64 *p, u64 old, u64 new);
+
 #include <asm-generic/cmpxchg-local.h>
 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#define cmpxchg64(ptr, o, n) __cmpxchg_u64((ptr), (o), (n))
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/lib/Kconfig b/lib/Kconfig
index d1573a16aa92..2b581a70ded2 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -500,6 +500,9 @@ config NLATTR
 config GENERIC_ATOMIC64
        bool
 
+config GENERIC_CMPXCHG64
+	bool
+
 config LRU_CACHE
 	tristate
 
diff --git a/lib/Makefile b/lib/Makefile
index 988949c4fd3a..4646a06ed418 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -172,6 +172,8 @@ obj-$(CONFIG_GENERIC_CSUM) += checksum.o
 
 obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o
 
+obj-$(CONFIG_GENERIC_CMPXCHG64) += cmpxchg64.o
+
 obj-$(CONFIG_ATOMIC64_SELFTEST) += atomic64_test.o
 
 obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o
diff --git a/lib/cmpxchg64.c b/lib/cmpxchg64.c
new file mode 100644
index 000000000000..239c43d05d00
--- /dev/null
+++ b/lib/cmpxchg64.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic implementation of cmpxchg64().
+ * Derived from implementation in arch/sparc/lib/atomic32.c
+ * and from locking code implemented in lib/atomic32.c.
+ */
+
+#include <linux/cache.h>
+#include <linux/export.h>
+#include <linux/irqflags.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/*
+ * We use a hashed array of spinlocks to provide exclusive access
+ * to each variable. Since this is expected to used on systems
+ * with small numbers of CPUs (<= 4 or so), we use a relatively
+ * small array of 16 spinlocks to avoid wasting too much memory
+ * on the spinlock array.
+ */
+#define NR_LOCKS	16
+
+/* Ensure that each lock is in a separate cacheline */
+static union {
+	raw_spinlock_t lock;
+	char pad[L1_CACHE_BYTES];
+} cmpxchg_lock[NR_LOCKS] __cacheline_aligned_in_smp = {
+	[0 ... (NR_LOCKS - 1)] = {
+		.lock =  __RAW_SPIN_LOCK_UNLOCKED(cmpxchg_lock.lock),
+	},
+};
+
+static inline raw_spinlock_t *lock_addr(const u64 *v)
+{
+	unsigned long addr = (unsigned long) v;
+
+	addr >>= L1_CACHE_SHIFT;
+	addr ^= (addr >> 8) ^ (addr >> 16);
+	return &cmpxchg_lock[addr & (NR_LOCKS - 1)].lock;
+}
+
+/*
+ * Generic version of __cmpxchg_u64, to be used for cmpxchg64().
+ * Takes u64 parameters.
+ */
+u64 __cmpxchg_u64(u64 *ptr, u64 old, u64 new)
+{
+	raw_spinlock_t *lock = lock_addr(ptr);
+	unsigned long flags;
+	u64 prev;
+
+	raw_spin_lock_irqsave(lock, flags);
+	prev = READ_ONCE(*ptr);
+	if (prev == old)
+		*ptr = new;
+	raw_spin_unlock_irqrestore(lock, flags);
+
+	return prev;
+}
+EXPORT_SYMBOL(__cmpxchg_u64);
-- 
2.7.4


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

end of thread, other threads:[~2018-11-05 14:26 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-31 19:52 [RFC PATCH] lib: Introduce generic __cmpxchg_u64() and use it where needed Guenter Roeck
2018-10-31 21:32 ` Paul Burton
2018-10-31 22:02   ` Guenter Roeck
2018-10-31 23:32     ` Paul Burton
2018-11-01  0:17       ` Trond Myklebust
2018-11-01 13:18         ` Mark Rutland
2018-11-01 14:59           ` Peter Zijlstra
2018-11-01 15:22             ` Trond Myklebust
2018-11-01 16:32               ` Peter Zijlstra
2018-11-01 16:59                 ` Eric Dumazet
2018-11-01 17:14                   ` Peter Zijlstra
2018-11-01 17:27                     ` Peter Zijlstra
2018-11-01 20:29                       ` Paul E. McKenney
2018-11-01 21:38                         ` Peter Zijlstra
2018-11-01 22:26                           ` Paul E. McKenney
2018-11-01 17:43                     ` Paul E. McKenney
2018-11-01 17:01                 ` Paul E. McKenney
2018-11-01 17:18                   ` Peter Zijlstra
2018-11-01 17:34                     ` Paul E. McKenney
2018-11-01 17:46                     ` Dmitry Vyukov
2018-11-01 21:45                       ` Peter Zijlstra
2018-11-02 10:56                   ` David Laight
2018-11-02 12:23                     ` Peter Zijlstra
2018-11-02 13:38                       ` Paul E. McKenney
2018-11-02 13:37                     ` Paul E. McKenney
2018-11-02 16:19                 ` Andrey Ryabinin
2018-11-05 10:38                   ` Peter Zijlstra
2018-11-05 14:24                   ` Peter Zijlstra
2018-11-01 17:51             ` [PATCH] SUNRPC: Use atomic(64)_t for seq_send(64) Paul Burton
2018-11-01 17:57               ` Trond Myklebust
2018-11-01 17:54         ` [RFC PATCH] lib: Introduce generic __cmpxchg_u64() and use it where needed Paul Burton
2018-11-01  1:18       ` Guenter Roeck
2018-11-01  6:30         ` Trond Myklebust
2018-11-01 15:28           ` Guenter Roeck

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).