Skip to contentSkip to conversation

Locking changes for v4.2

GIT PULL Ingo Molnar 3 participants 4 messages Jun 22, 2015 – Jun 26, 2015

Subsystems (24)
Documentation Arm (32-bit) x86 VFS +20 more subsystems
lore
Share & tools
lore
#0 lore raw

Linus,

Please pull the latest locking-core-for-linus git tree from:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking-core-for-linus

# HEAD: 68722101ec3a0e179408a13708dd020e04f54aab locking/lockdep: Remove hard coded array size dependency

The main changes are:

- 'qspinlock' support, enabled on x86: queued spinlocks - these are now the spinlock variant used by x86 as they outperform ticket spinlocks in every category. (Waiman Long)

- 'pvqspinlock' support on x86: paravirtualized variant of queued spinlocks. (Waiman Long, Peter Zijlstra)

- 'qrwlock' support, enabled on x86: queued rwlocks. Similar to queued spinlocks, they are now the variant used by x86:

CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_QUEUED_RWLOCKS=y

- various lockdep fixlets

- various locking primitives cleanups, further WRITE_ONCE() propagation

Thanks,

Ingo

------------------>
Borislav Petkov (1):
lockdep: Do not break user-visible string

David Vrabel (1):
locking/pvqspinlock, x86: Enable PV qspinlock for Xen

George Beshers (1):
locking/lockdep: Remove hard coded array size dependency

Ingo Molnar (1):
locking/pvqspinlock: Rename QUEUED_SPINLOCK to QUEUED_SPINLOCKS

Peter Zijlstra (2):
locking/arch: Add WRITE_ONCE() to set_mb() locking/arch: Rename set_mb() to smp_store_mb()

Peter Zijlstra (Intel) (4):
locking/qspinlock: Add pending bit
locking/qspinlock: Optimize for smaller NR_CPUS locking/qspinlock: Revert to test-and-set on hypervisors locking/pvqspinlock, x86: Implement the paravirt qspinlock call patching

Preeti U Murthy (1):
kernel: Replace reference to ASSIGN_ONCE() with WRITE_ONCE() in comment

Sebastian Andrzej Siewior (1):
locking/rtmutex: Drop usage of __HAVE_ARCH_CMPXCHG

Thomas Gleixner (2):
arch: Remove __ARCH_HAVE_CMPXCHG
rtmutex: Warn if trylock is called from hard/softirq context

Waiman Long (10):
locking/rwsem: Reduce spinlock contention in wakeup after up_read()/up_write() locking/qspinlock: Introduce a simple generic 4-byte queued spinlock locking/qspinlock, x86: Enable x86-64 to use queued spinlocks locking/qspinlock: Extract out code snippets for the next patch locking/qspinlock: Use a simple write to grab the lock locking/pvqspinlock: Implement simple paravirt support for the qspinlock locking/pvqspinlock, x86: Enable PV qspinlock for KVM locking/pvqspinlock: Replace xchg() by the more descriptive set_mb() locking/qrwlock: Rename QUEUE_RWLOCK to QUEUED_RWLOCKS locking/qrwlock: Don't contend with readers when setting _QW_WAITING

 Documentation/memory-barriers.txt         |   6 +-
 arch/alpha/include/asm/cmpxchg.h          |   2 -
 arch/arm/include/asm/barrier.h            |   2 +-
 arch/arm64/include/asm/barrier.h          |   2 +-
 arch/avr32/include/asm/cmpxchg.h          |   2 -
 arch/hexagon/include/asm/cmpxchg.h        |   1 -
 arch/ia64/include/asm/barrier.h           |   7 +-
 arch/ia64/include/uapi/asm/cmpxchg.h      |   2 -
 arch/m32r/include/asm/cmpxchg.h           |   2 -
 arch/m68k/include/asm/cmpxchg.h           |   1 -
 arch/metag/include/asm/barrier.h          |   2 +-
 arch/metag/include/asm/cmpxchg.h          |   2 -
 arch/mips/include/asm/barrier.h           |   4 +-
 arch/mips/include/asm/cmpxchg.h           |   2 -
 arch/parisc/include/asm/cmpxchg.h         |   2 -
 arch/powerpc/include/asm/barrier.h        |   2 +-
 arch/powerpc/include/asm/cmpxchg.h        |   1 -
 arch/s390/include/asm/barrier.h           |   2 +-
 arch/s390/include/asm/cmpxchg.h           |   2 -
 arch/score/include/asm/cmpxchg.h          |   2 -
 arch/sh/include/asm/barrier.h             |   2 +-
 arch/sh/include/asm/cmpxchg.h             |   2 -
 arch/sparc/include/asm/barrier_64.h       |   4 +-
 arch/sparc/include/asm/cmpxchg_32.h       |   1 -
 arch/sparc/include/asm/cmpxchg_64.h       |   2 -
 arch/tile/include/asm/atomic_64.h         |   3 -
 arch/x86/Kconfig                          |   5 +-
 arch/x86/include/asm/barrier.h            |   4 +-
 arch/x86/include/asm/cmpxchg.h            |   2 -
 arch/x86/include/asm/paravirt.h           |  29 +-
 arch/x86/include/asm/paravirt_types.h     |  10 +
 arch/x86/include/asm/qspinlock.h          |  57 ++++
 arch/x86/include/asm/qspinlock_paravirt.h |   6 +
 arch/x86/include/asm/spinlock.h           |   5 +
 arch/x86/include/asm/spinlock_types.h     |   4 +
 arch/x86/kernel/kvm.c                     |  43 +++
 arch/x86/kernel/paravirt-spinlocks.c      |  24 +-
 arch/x86/kernel/paravirt_patch_32.c       |  22 +-
 arch/x86/kernel/paravirt_patch_64.c       |  22 +-
 arch/x86/um/asm/barrier.h                 |   3 +-
 arch/x86/xen/spinlock.c                   |  64 +++-
 fs/select.c                               |   6 +-
 include/asm-generic/barrier.h             |   4 +-
 include/asm-generic/cmpxchg.h             |   3 -
 include/asm-generic/qspinlock.h           | 139 +++++++++
 include/asm-generic/qspinlock_types.h     |  79 +++++
 include/linux/compiler.h                  |   4 +-
 include/linux/lockdep.h                   |   4 +-
 include/linux/osq_lock.h                  |   5 +
 include/linux/sched.h                     |   8 +-
 kernel/Kconfig.locks                      |  13 +-
 kernel/futex.c                            |   2 +-
 kernel/locking/Makefile                   |   3 +-
 kernel/locking/lockdep.c                  |   3 +-
 kernel/locking/mcs_spinlock.h             |   1 +
 kernel/locking/qrwlock.c                  |  30 +-
 kernel/locking/qspinlock.c                | 473 ++++++++++++++++++++++++++++++
 kernel/locking/qspinlock_paravirt.h       | 325 ++++++++++++++++++++
 kernel/locking/rtmutex.c                  |  13 +-
 kernel/locking/rwsem-xadd.c               |  44 +++
 kernel/sched/wait.c                       |   4 +-
 61 files changed, 1423 insertions(+), 102 deletions(-)
 create mode 100644 arch/x86/include/asm/qspinlock.h
 create mode 100644 arch/x86/include/asm/qspinlock_paravirt.h
 create mode 100644 include/asm-generic/qspinlock.h
 create mode 100644 include/asm-generic/qspinlock_types.h
 create mode 100644 kernel/locking/qspinlock.c
 create mode 100644 kernel/locking/qspinlock_paravirt.h
Documentation/memory-barriers.txt +3 -3
index f95746189b5d..fe4020e4b468 100644
@@ -1662,7 +1662,7 @@ CPU from reordering them.
 
 There are some more advanced barrier functions:
 
- (*) set_mb(var, value)
+ (*) smp_store_mb(var, value)
 
      This assigns the value to the variable and then inserts a full memory
      barrier after it, depending on the function.  It isn't guaranteed to
@@ -1975,7 +1975,7 @@ A general memory barrier is interpolated automatically by set_current_state()
 	CPU 1
 	===============================
 	set_current_state();
-	  set_mb();
+	  smp_store_mb();
 	    STORE current->state
 	    <general barrier>
 	LOAD event_indicated
@@ -2016,7 +2016,7 @@ something up.  The barrier occurs before the task state is cleared, and so sits
 	CPU 1				CPU 2
 	===============================	===============================
 	set_current_state();		STORE event_indicated
-	  set_mb();			wake_up();
+	  smp_store_mb();		wake_up();
 	    STORE current->state	  <write barrier>
 	    <general barrier>		  STORE current->state
 	LOAD event_indicated
arch/alpha/include/asm/cmpxchg.h +0 -2
index 429e8cd0d78e..e5117766529e 100644
@@ -66,6 +66,4 @@
 #undef __ASM__MB
 #undef ____cmpxchg
 
-#define __HAVE_ARCH_CMPXCHG 1
-
 #endif /* _ALPHA_CMPXCHG_H */
arch/arm/include/asm/barrier.h +1 -1
index d2f81e6b8c1c..6c2327e1c732 100644
@@ -81,7 +81,7 @@ do {									\
 #define read_barrier_depends()		do { } while(0)
 #define smp_read_barrier_depends()	do { } while(0)
 
-#define set_mb(var, value)	do { var = value; smp_mb(); } while (0)
+#define smp_store_mb(var, value)	do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 
 #define smp_mb__before_atomic()	smp_mb()
 #define smp_mb__after_atomic()	smp_mb()
arch/arm64/include/asm/barrier.h +1 -1
index 71f19c4dc0de..0fa47c4275cb 100644
@@ -114,7 +114,7 @@ do {									\
 #define read_barrier_depends()		do { } while(0)
 #define smp_read_barrier_depends()	do { } while(0)
 
-#define set_mb(var, value)	do { var = value; smp_mb(); } while (0)
+#define smp_store_mb(var, value)	do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 #define nop()		asm volatile("nop");
 
 #define smp_mb__before_atomic()	smp_mb()
arch/avr32/include/asm/cmpxchg.h +0 -2
index 962a6aeab787..366bbeaeb405 100644
@@ -70,8 +70,6 @@ extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels(
    if something tries to do an invalid cmpxchg().  */
 extern void __cmpxchg_called_with_bad_pointer(void);
 
-#define __HAVE_ARCH_CMPXCHG 1
-
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 				      unsigned long new, int size)
 {
arch/hexagon/include/asm/cmpxchg.h +0 -1
index 9e7802911a57..a6e34e2acbba 100644
@@ -64,7 +64,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
  *  looks just like atomic_cmpxchg on our arch currently with a bunch of
  *  variable casting.
  */
-#define __HAVE_ARCH_CMPXCHG 1
 
 #define cmpxchg(ptr, old, new)					\
 ({								\
arch/ia64/include/asm/barrier.h +1 -6
index f6769eb2bbf9..843ba435e43b 100644
@@ -77,12 +77,7 @@ do {									\
 	___p1;								\
 })
 
-/*
- * XXX check on this ---I suspect what Linus really wants here is
- * acquire vs release semantics but we can't discuss this stuff with
- * Linus just yet.  Grrr...
- */
-#define set_mb(var, value)	do { (var) = (value); mb(); } while (0)
+#define smp_store_mb(var, value)	do { WRITE_ONCE(var, value); mb(); } while (0)
 
 /*
  * The group barrier in front of the rsm & ssm are necessary to ensure
arch/ia64/include/uapi/asm/cmpxchg.h +0 -2
index f35109b1d907..a0e3620f8f13 100644
@@ -61,8 +61,6 @@ extern void ia64_xchg_called_with_bad_pointer(void);
  * indicated by comparing RETURN with OLD.
  */
 
-#define __HAVE_ARCH_CMPXCHG 1
-
 /*
  * This function doesn't exist, so you'll get a linker error
  * if something tries to do an invalid cmpxchg().
arch/m32r/include/asm/cmpxchg.h +0 -2
index de651db20b43..14bf9b739dd2 100644
@@ -107,8 +107,6 @@ __xchg_local(unsigned long x, volatile void *ptr, int size)
 	((__typeof__(*(ptr)))__xchg_local((unsigned long)(x), (ptr),	\
 			sizeof(*(ptr))))
 
-#define __HAVE_ARCH_CMPXCHG	1
-
 static inline unsigned long
 __cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new)
 {
arch/m68k/include/asm/cmpxchg.h +0 -1
index bc755bc620ad..83b1df80f0ac 100644
@@ -90,7 +90,6 @@ extern unsigned long __invalid_cmpxchg_size(volatile void *,
  * indicated by comparing RETURN with OLD.
  */
 #ifdef CONFIG_RMW_INSNS
-#define __HAVE_ARCH_CMPXCHG	1
 
 static inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
 				      unsigned long new, int size)
arch/metag/include/asm/barrier.h +1 -1
index d703d8e26a65..5a696e507930 100644
@@ -84,7 +84,7 @@ static inline void fence(void)
 #define read_barrier_depends()		do { } while (0)
 #define smp_read_barrier_depends()	do { } while (0)
 
-#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 
 #define smp_store_release(p, v)						\
 do {									\
arch/metag/include/asm/cmpxchg.h +0 -2
index b1bc1be8540f..be29e3e44321 100644
@@ -51,8 +51,6 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 	return old;
 }
 
-#define __HAVE_ARCH_CMPXCHG 1
-
 #define cmpxchg(ptr, o, n)						\
 	({								\
 		__typeof__(*(ptr)) _o_ = (o);				\
arch/mips/include/asm/barrier.h +2 -2
index 2b8bbbcb9be0..7ecba84656d4 100644
@@ -112,8 +112,8 @@
 #define __WEAK_LLSC_MB		"		\n"
 #endif
 
-#define set_mb(var, value) \
-	do { var = value; smp_mb(); } while (0)
+#define smp_store_mb(var, value) \
+	do { WRITE_ONCE(var, value); smp_mb(); } while (0)
 
 #define smp_llsc_mb()	__asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
 
arch/mips/include/asm/cmpxchg.h +0 -2
index 412f945f1f5e..b71ab4a5fd50 100644
@@ -138,8 +138,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
 		__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))));	\
 })
 
-#define __HAVE_ARCH_CMPXCHG 1
-
 #define __cmpxchg_asm(ld, st, m, old, new)				\
 ({									\
 	__typeof(*(m)) __ret;						\
arch/parisc/include/asm/cmpxchg.h +0 -2
index dbd13354ec41..0a90b965cccb 100644
@@ -46,8 +46,6 @@ __xchg(unsigned long x, __volatile__ void *ptr, int size)
 #define xchg(ptr, x) \
 	((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
 
-#define __HAVE_ARCH_CMPXCHG	1
-
 /* bug catcher for when unsupported size is used - won't link */
 extern void __cmpxchg_called_with_bad_pointer(void);
 
arch/powerpc/include/asm/barrier.h +1 -1
index a3bf5be111ff..39505d660a70 100644
@@ -34,7 +34,7 @@
 #define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
 #define wmb()  __asm__ __volatile__ ("sync" : : : "memory")
 
-#define set_mb(var, value)	do { var = value; mb(); } while (0)
+#define smp_store_mb(var, value)	do { WRITE_ONCE(var, value); mb(); } while (0)
 
 #ifdef __SUBARCH_HAS_LWSYNC
 #    define SMPWMB      LWSYNC
arch/powerpc/include/asm/cmpxchg.h +0 -1
index d463c68fe7f0..ad6263cffb0f 100644
@@ -144,7 +144,6 @@ __xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
  * Compare and exchange - if *p == old, set it to new,
  * and return the old value of *p.
  */
-#define __HAVE_ARCH_CMPXCHG	1
 
 static __always_inline unsigned long
 __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
arch/s390/include/asm/barrier.h +1 -1
index 8d724718ec21..e6f8615a11eb 100644
@@ -36,7 +36,7 @@
 #define smp_mb__before_atomic()		smp_mb()
 #define smp_mb__after_atomic()		smp_mb()
 
-#define set_mb(var, value)		do { var = value; mb(); } while (0)
+#define smp_store_mb(var, value)		do { WRITE_ONCE(var, value); mb(); } while (0)
 
 #define smp_store_release(p, v)						\
 do {									\
arch/s390/include/asm/cmpxchg.h +0 -2
index 4eadec466b8c..411464f4c97a 100644
@@ -32,8 +32,6 @@
 	__old;								\
 })
 
-#define __HAVE_ARCH_CMPXCHG
-
 #define __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, insn)		\
 ({									\
 	register __typeof__(*(p1)) __old1 asm("2") = (o1);		\
arch/score/include/asm/cmpxchg.h +0 -2
index f384839c3ee5..cc3f6420b71c 100644
@@ -42,8 +42,6 @@ static inline unsigned long __cmpxchg(volatile unsigned long *m,
 					(unsigned long)(o),	\
 					(unsigned long)(n)))
 
-#define __HAVE_ARCH_CMPXCHG	1
-
 #include <asm-generic/cmpxchg-local.h>
 
 #endif /* _ASM_SCORE_CMPXCHG_H */
arch/sh/include/asm/barrier.h +1 -1
index 43715308b068..bf91037db4e0 100644
@@ -32,7 +32,7 @@
 #define ctrl_barrier()	__asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
 #endif
 
-#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
+#define smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
 
 #include <asm-generic/barrier.h>
 
arch/sh/include/asm/cmpxchg.h +0 -2
index f6bd1406b897..85c97b188d71 100644
@@ -46,8 +46,6 @@ extern void __xchg_called_with_bad_pointer(void);
  * if something tries to do an invalid cmpxchg(). */
 extern void __cmpxchg_called_with_bad_pointer(void);
 
-#define __HAVE_ARCH_CMPXCHG 1
-
 static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
 		unsigned long new, int size)
 {
arch/sparc/include/asm/barrier_64.h +2 -2
index 76648941fea7..809941e33e12 100644
@@ -40,8 +40,8 @@ do {	__asm__ __volatile__("ba,pt	%%xcc, 1f\n\t" \
 #define dma_rmb()	rmb()
 #define dma_wmb()	wmb()
 
-#define set_mb(__var, __value) \
-	do { __var = __value; membar_safe("#StoreLoad"); } while(0)
+#define smp_store_mb(__var, __value) \
+	do { WRITE_ONCE(__var, __value); membar_safe("#StoreLoad"); } while(0)
 
 #ifdef CONFIG_SMP
 #define smp_mb()	mb()
arch/sparc/include/asm/cmpxchg_32.h +0 -1
index d38b52dca216..83ffb83c5397 100644
@@ -34,7 +34,6 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int
  *
  * Cribbed from <asm-parisc/atomic.h>
  */
-#define __HAVE_ARCH_CMPXCHG	1
 
 /* bug catcher for when unsupported size is used - won't link */
 void __cmpxchg_called_with_bad_pointer(void);
arch/sparc/include/asm/cmpxchg_64.h +0 -2
index 0e1ed6cfbf68..faa2f61058c2 100644
@@ -65,8 +65,6 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
 
 #include <asm-generic/cmpxchg-local.h>
 
-#define __HAVE_ARCH_CMPXCHG 1
-
 static inline unsigned long
 __cmpxchg_u32(volatile int *m, int old, int new)
 {
arch/tile/include/asm/atomic_64.h +0 -3
index 7b11c5fadd42..0496970cef82 100644
@@ -105,9 +105,6 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u)
 
 #define atomic64_inc_not_zero(v)	atomic64_add_unless((v), 1, 0)
 
-/* Define this to indicate that cmpxchg is an efficient operation. */
-#define __HAVE_ARCH_CMPXCHG
-
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_TILE_ATOMIC_64_H */
arch/x86/Kconfig +3 -2
index 226d5696e1d1..4e986e809861 100644
@@ -127,7 +127,8 @@ config X86
 	select MODULES_USE_ELF_RELA if X86_64
 	select CLONE_BACKWARDS if X86_32
 	select ARCH_USE_BUILTIN_BSWAP
-	select ARCH_USE_QUEUE_RWLOCK
+	select ARCH_USE_QUEUED_SPINLOCKS
+	select ARCH_USE_QUEUED_RWLOCKS
 	select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION
 	select OLD_SIGACTION if X86_32
 	select COMPAT_OLD_SIGACTION if IA32_EMULATION
@@ -666,7 +667,7 @@ config PARAVIRT_DEBUG
 config PARAVIRT_SPINLOCKS
 	bool "Paravirtualization layer for spinlocks"
 	depends on PARAVIRT && SMP
-	select UNINLINE_SPIN_UNLOCK
+	select UNINLINE_SPIN_UNLOCK if !QUEUED_SPINLOCKS
 	---help---
 	  Paravirtualized spinlocks allow a pvops backend to replace the
 	  spinlock implementation with something virtualization-friendly
arch/x86/include/asm/barrier.h +2 -2
index 959e45b81fe2..e51a8f803f55 100644
@@ -35,12 +35,12 @@
 #define smp_mb()	mb()
 #define smp_rmb()	dma_rmb()
 #define smp_wmb()	barrier()
-#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
+#define smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
 #else /* !SMP */
 #define smp_mb()	barrier()
 #define smp_rmb()	barrier()
 #define smp_wmb()	barrier()
-#define set_mb(var, value) do { var = value; barrier(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0)
 #endif /* SMP */
 
 #define read_barrier_depends()		do { } while (0)
arch/x86/include/asm/cmpxchg.h +0 -2
index 99c105d78b7e..ad19841eddfe 100644
@@ -4,8 +4,6 @@
 #include <linux/compiler.h>
 #include <asm/alternative.h> /* Provides LOCK_PREFIX */
 
-#define __HAVE_ARCH_CMPXCHG 1
-
 /*
  * Non-existant functions to indicate usage errors at link time
  * (or compile-time if the compiler implements __compiletime_error().
arch/x86/include/asm/paravirt.h +28 -1
index 8957810ad7d1..d143bfad45d7 100644
@@ -712,6 +712,31 @@ static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PARAVIRT_SPINLOCKS)
 
+#ifdef CONFIG_QUEUED_SPINLOCKS
+
+static __always_inline void pv_queued_spin_lock_slowpath(struct qspinlock *lock,
+							u32 val)
+{
+	PVOP_VCALL2(pv_lock_ops.queued_spin_lock_slowpath, lock, val);
+}
+
+static __always_inline void pv_queued_spin_unlock(struct qspinlock *lock)
+{
+	PVOP_VCALLEE1(pv_lock_ops.queued_spin_unlock, lock);
+}
+
+static __always_inline void pv_wait(u8 *ptr, u8 val)
+{
+	PVOP_VCALL2(pv_lock_ops.wait, ptr, val);
+}
+
+static __always_inline void pv_kick(int cpu)
+{
+	PVOP_VCALL1(pv_lock_ops.kick, cpu);
+}
+
+#else /* !CONFIG_QUEUED_SPINLOCKS */
+
 static __always_inline void __ticket_lock_spinning(struct arch_spinlock *lock,
 							__ticket_t ticket)
 {
@@ -724,7 +749,9 @@ static __always_inline void __ticket_unlock_kick(struct arch_spinlock *lock,
 	PVOP_VCALL2(pv_lock_ops.unlock_kick, lock, ticket);
 }
 
-#endif
+#endif /* CONFIG_QUEUED_SPINLOCKS */
+
+#endif /* SMP && PARAVIRT_SPINLOCKS */
 
 #ifdef CONFIG_X86_32
 #define PV_SAVE_REGS "pushl %ecx; pushl %edx;"
arch/x86/include/asm/paravirt_types.h +10 -0
index f7b0b5c112f2..8766c7c395c2 100644
@@ -333,9 +333,19 @@ struct arch_spinlock;
 typedef u16 __ticket_t;
 #endif
 
+struct qspinlock;
+
 struct pv_lock_ops {
+#ifdef CONFIG_QUEUED_SPINLOCKS
+	void (*queued_spin_lock_slowpath)(struct qspinlock *lock, u32 val);
+	struct paravirt_callee_save queued_spin_unlock;
+
+	void (*wait)(u8 *ptr, u8 val);
+	void (*kick)(int cpu);
+#else /* !CONFIG_QUEUED_SPINLOCKS */
 	struct paravirt_callee_save lock_spinning;
 	void (*unlock_kick)(struct arch_spinlock *lock, __ticket_t ticket);
+#endif /* !CONFIG_QUEUED_SPINLOCKS */
 };
 
 /* This contains all the paravirt structures: we get a convenient
arch/x86/include/asm/qspinlock.h new file +57 -0

57 lines not on this page · raw message

arch/x86/include/asm/qspinlock_paravirt.h new file +6 -0
new file mode 100644
index 000000000000..b002e711ba88
@@ -0,0 +1,6 @@
+#ifndef __ASM_QSPINLOCK_PARAVIRT_H
+#define __ASM_QSPINLOCK_PARAVIRT_H
+
+PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock);
+
+#endif
arch/x86/include/asm/spinlock.h +5 -0
index 64b611782ef0..be0a05913b91 100644
@@ -42,6 +42,10 @@
 extern struct static_key paravirt_ticketlocks_enabled;
 static __always_inline bool static_key_false(struct static_key *key);
 
+#ifdef CONFIG_QUEUED_SPINLOCKS
+#include <asm/qspinlock.h>
+#else
+
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
 
 static inline void __ticket_enter_slowpath(arch_spinlock_t *lock)
@@ -196,6 +200,7 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
 		cpu_relax();
 	}
 }
+#endif /* CONFIG_QUEUED_SPINLOCKS */
 
 /*
  * Read-write spinlocks, allowing multiple readers
arch/x86/include/asm/spinlock_types.h +4 -0
index 5f9d7572d82b..65c3e37f879a 100644
@@ -23,6 +23,9 @@ typedef u32 __ticketpair_t;
 
 #define TICKET_SHIFT	(sizeof(__ticket_t) * 8)
 
+#ifdef CONFIG_QUEUED_SPINLOCKS
+#include <asm-generic/qspinlock_types.h>
+#else
 typedef struct arch_spinlock {
 	union {
 		__ticketpair_t head_tail;
@@ -33,6 +36,7 @@ typedef struct arch_spinlock {
 } arch_spinlock_t;
 
 #define __ARCH_SPIN_LOCK_UNLOCKED	{ { 0 } }
+#endif /* CONFIG_QUEUED_SPINLOCKS */
 
 #include <asm-generic/qrwlock_types.h>
 
arch/x86/kernel/kvm.c +43 -0

63 lines not on this page · raw message

arch/x86/kernel/paravirt-spinlocks.c +23 -1
index bbb6c7316341..33ee3e0efd65 100644
@@ -8,11 +8,33 @@
 
 #include <asm/paravirt.h>
 
+#ifdef CONFIG_QUEUED_SPINLOCKS
+__visible void __native_queued_spin_unlock(struct qspinlock *lock)
+{
+	native_queued_spin_unlock(lock);
+}
+
+PV_CALLEE_SAVE_REGS_THUNK(__native_queued_spin_unlock);
+
+bool pv_is_native_spin_unlock(void)
+{
+	return pv_lock_ops.queued_spin_unlock.func ==
+		__raw_callee_save___native_queued_spin_unlock;
+}
+#endif
+
 struct pv_lock_ops pv_lock_ops = {
 #ifdef CONFIG_SMP
+#ifdef CONFIG_QUEUED_SPINLOCKS
+	.queued_spin_lock_slowpath = native_queued_spin_lock_slowpath,
+	.queued_spin_unlock = PV_CALLEE_SAVE(__native_queued_spin_unlock),
+	.wait = paravirt_nop,
+	.kick = paravirt_nop,
+#else /* !CONFIG_QUEUED_SPINLOCKS */
 	.lock_spinning = __PV_IS_CALLEE_SAVE(paravirt_nop),
 	.unlock_kick = paravirt_nop,
-#endif
+#endif /* !CONFIG_QUEUED_SPINLOCKS */
+#endif /* SMP */
 };
 EXPORT_SYMBOL(pv_lock_ops);
 
arch/x86/kernel/paravirt_patch_32.c +18 -4
index d9f32e6d6ab6..e1b013696dde 100644
@@ -12,6 +12,10 @@ DEF_NATIVE(pv_mmu_ops, read_cr3, "mov %cr3, %eax");
 DEF_NATIVE(pv_cpu_ops, clts, "clts");
 DEF_NATIVE(pv_cpu_ops, read_tsc, "rdtsc");
 
+#if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS)
+DEF_NATIVE(pv_lock_ops, queued_spin_unlock, "movb $0, (%eax)");
+#endif
+
 unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len)
 {
 	/* arg in %eax, return in %eax */
@@ -24,6 +28,8 @@ unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len)
 	return 0;
 }
 
+extern bool pv_is_native_spin_unlock(void);
+
 unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
 		      unsigned long addr, unsigned len)
 {
@@ -47,14 +53,22 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
 		PATCH_SITE(pv_mmu_ops, write_cr3);
 		PATCH_SITE(pv_cpu_ops, clts);
 		PATCH_SITE(pv_cpu_ops, read_tsc);
-
-	patch_site:
-		ret = paravirt_patch_insns(ibuf, len, start, end);
-		break;
+#if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS)
+		case PARAVIRT_PATCH(pv_lock_ops.queued_spin_unlock):
+			if (pv_is_native_spin_unlock()) {
+				start = start_pv_lock_ops_queued_spin_unlock;
+				end   = end_pv_lock_ops_queued_spin_unlock;
+				goto patch_site;
+			}
+#endif
 
 	default:
 		ret = paravirt_patch_default(type, clobbers, ibuf, addr, len);
 		break;
+
+patch_site:
+		ret = paravirt_patch_insns(ibuf, len, start, end);
+		break;
 	}
 #undef PATCH_SITE
 	return ret;
arch/x86/kernel/paravirt_patch_64.c +18 -4
index a1da6737ba5b..a1fa86782186 100644
@@ -21,6 +21,10 @@ DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs");
 DEF_NATIVE(, mov32, "mov %edi, %eax");
 DEF_NATIVE(, mov64, "mov %rdi, %rax");
 
+#if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS)
+DEF_NATIVE(pv_lock_ops, queued_spin_unlock, "movb $0, (%rdi)");
+#endif
+
 unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len)
 {
 	return paravirt_patch_insns(insnbuf, len,
@@ -33,6 +37,8 @@ unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len)
 				    start__mov64, end__mov64);
 }
 
+extern bool pv_is_native_spin_unlock(void);
+
 unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
 		      unsigned long addr, unsigned len)
 {
@@ -59,14 +65,22 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
 		PATCH_SITE(pv_cpu_ops, clts);
 		PATCH_SITE(pv_mmu_ops, flush_tlb_single);
 		PATCH_SITE(pv_cpu_ops, wbinvd);
-
-	patch_site:
-		ret = paravirt_patch_insns(ibuf, len, start, end);
-		break;
+#if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS)
+		case PARAVIRT_PATCH(pv_lock_ops.queued_spin_unlock):
+			if (pv_is_native_spin_unlock()) {
+				start = start_pv_lock_ops_queued_spin_unlock;
+				end   = end_pv_lock_ops_queued_spin_unlock;
+				goto patch_site;
+			}
+#endif
 
 	default:
 		ret = paravirt_patch_default(type, clobbers, ibuf, addr, len);
 		break;
+
+patch_site:
+		ret = paravirt_patch_insns(ibuf, len, start, end);
+		break;
 	}
 #undef PATCH_SITE
 	return ret;
arch/x86/um/asm/barrier.h +2 -1
index 7e8a1a650435..b9531d343134 100644
@@ -39,7 +39,8 @@
 #define smp_mb()	barrier()
 #define smp_rmb()	barrier()
 #define smp_wmb()	barrier()
-#define set_mb(var, value) do { var = value; barrier(); } while (0)
+
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0)
 
 #define read_barrier_depends()		do { } while (0)
 #define smp_read_barrier_depends()	do { } while (0)
arch/x86/xen/spinlock.c +60 -4

99 lines not on this page · raw message

fs/select.c +3 -3
index f684c750e08a..015547330e88 100644
@@ -189,7 +189,7 @@ static int __pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
 	 * doesn't imply write barrier and the users expect write
 	 * barrier semantics on wakeup functions.  The following
 	 * smp_wmb() is equivalent to smp_wmb() in try_to_wake_up()
-	 * and is paired with set_mb() in poll_schedule_timeout.
+	 * and is paired with smp_store_mb() in poll_schedule_timeout.
 	 */
 	smp_wmb();
 	pwq->triggered = 1;
@@ -244,7 +244,7 @@ int poll_schedule_timeout(struct poll_wqueues *pwq, int state,
 	/*
 	 * Prepare for the next iteration.
 	 *
-	 * The following set_mb() serves two purposes.  First, it's
+	 * The following smp_store_mb() serves two purposes.  First, it's
 	 * the counterpart rmb of the wmb in pollwake() such that data
 	 * written before wake up is always visible after wake up.
 	 * Second, the full barrier guarantees that triggered clearing
@@ -252,7 +252,7 @@ int poll_schedule_timeout(struct poll_wqueues *pwq, int state,
 	 * this problem doesn't exist for the first iteration as
 	 * add_wait_queue() has full barrier semantics.
 	 */
-	set_mb(pwq->triggered, 0);
+	smp_store_mb(pwq->triggered, 0);
 
 	return rc;
 }
include/asm-generic/barrier.h +2 -2
index f5c40b0fadc2..e6a83d712ef6 100644
@@ -66,8 +66,8 @@
 #define smp_read_barrier_depends()	do { } while (0)
 #endif
 
-#ifndef set_mb
-#define set_mb(var, value)  do { (var) = (value); mb(); } while (0)
+#ifndef smp_store_mb
+#define smp_store_mb(var, value)  do { WRITE_ONCE(var, value); mb(); } while (0)
 #endif
 
 #ifndef smp_mb__before_atomic
include/asm-generic/cmpxchg.h +0 -3
index 811fb1e9b061..3766ab34aa45 100644
@@ -86,9 +86,6 @@ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
 
 /*
  * Atomic compare and exchange.
- *
- * Do not define __HAVE_ARCH_CMPXCHG because we want to use it to check whether
- * a cmpxchg primitive faster than repeated local irq save/restore exists.
  */
 #include <asm-generic/cmpxchg-local.h>
 
include/asm-generic/qspinlock.h new file +139 -0

139 lines not on this page · raw message

include/asm-generic/qspinlock_types.h new file +79 -0

79 lines not on this page · raw message

include/linux/compiler.h +2 -2
index 867722591be2..03e227ba481c 100644
@@ -250,7 +250,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
 	({ union { typeof(x) __val; char __c[1]; } __u; __read_once_size(&(x), __u.__c, sizeof(x)); __u.__val; })
 
 #define WRITE_ONCE(x, val) \
-	({ typeof(x) __val = (val); __write_once_size(&(x), &__val, sizeof(__val)); __val; })
+	({ union { typeof(x) __val; char __c[1]; } __u = { .__val = (val) }; __write_once_size(&(x), __u.__c, sizeof(x)); __u.__val; })
 
 #endif /* __KERNEL__ */
 
@@ -450,7 +450,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
  * with an explicit memory barrier or atomic instruction that provides the
  * required ordering.
  *
- * If possible use READ_ONCE/ASSIGN_ONCE instead.
+ * If possible use READ_ONCE()/WRITE_ONCE() instead.
  */
 #define __ACCESS_ONCE(x) ({ \
 	 __maybe_unused typeof(x) __var = (__force typeof(x)) 0; \
include/linux/lockdep.h +2 -2
index 066ba4157541..2722111591a3 100644
@@ -130,8 +130,8 @@ enum bounce_type {
 };
 
 struct lock_class_stats {
-	unsigned long			contention_point[4];
-	unsigned long			contending_point[4];
+	unsigned long			contention_point[LOCKSTAT_POINTS];
+	unsigned long			contending_point[LOCKSTAT_POINTS];
 	struct lock_time		read_waittime;
 	struct lock_time		write_waittime;
 	struct lock_time		read_holdtime;
include/linux/osq_lock.h +5 -0
index 3a6490e81b28..703ea5c30a33 100644
@@ -32,4 +32,9 @@ static inline void osq_lock_init(struct optimistic_spin_queue *lock)
 extern bool osq_lock(struct optimistic_spin_queue *lock);
 extern void osq_unlock(struct optimistic_spin_queue *lock);
 
+static inline bool osq_is_locked(struct optimistic_spin_queue *lock)
+{
+	return atomic_read(&lock->tail) != OSQ_UNLOCKED_VAL;
+}
+
 #endif
include/linux/sched.h +4 -4
index 26a2e6122734..18f197223ebd 100644
@@ -252,7 +252,7 @@ extern char ___assert_task_state[1 - 2*!!(
 #define set_task_state(tsk, state_value)			\
 	do {							\
 		(tsk)->task_state_change = _THIS_IP_;		\
-		set_mb((tsk)->state, (state_value));		\
+		smp_store_mb((tsk)->state, (state_value));		\
 	} while (0)
 
 /*
@@ -274,7 +274,7 @@ extern char ___assert_task_state[1 - 2*!!(
 #define set_current_state(state_value)				\
 	do {							\
 		current->task_state_change = _THIS_IP_;		\
-		set_mb(current->state, (state_value));		\
+		smp_store_mb(current->state, (state_value));		\
 	} while (0)
 
 #else
@@ -282,7 +282,7 @@ extern char ___assert_task_state[1 - 2*!!(
 #define __set_task_state(tsk, state_value)		\
 	do { (tsk)->state = (state_value); } while (0)
 #define set_task_state(tsk, state_value)		\
-	set_mb((tsk)->state, (state_value))
+	smp_store_mb((tsk)->state, (state_value))
 
 /*
  * set_current_state() includes a barrier so that the write of current->state
@@ -298,7 +298,7 @@ extern char ___assert_task_state[1 - 2*!!(
 #define __set_current_state(state_value)		\
 	do { current->state = (state_value); } while (0)
 #define set_current_state(state_value)			\
-	set_mb(current->state, (state_value))
+	smp_store_mb(current->state, (state_value))
 
 #endif
 
kernel/Kconfig.locks +10 -3
index 08561f1acd13..ebdb0043203a 100644
@@ -235,9 +235,16 @@ config LOCK_SPIN_ON_OWNER
        def_bool y
        depends on MUTEX_SPIN_ON_OWNER || RWSEM_SPIN_ON_OWNER
 
-config ARCH_USE_QUEUE_RWLOCK
+config ARCH_USE_QUEUED_SPINLOCKS
 	bool
 
-config QUEUE_RWLOCK
-	def_bool y if ARCH_USE_QUEUE_RWLOCK
+config QUEUED_SPINLOCKS
+	def_bool y if ARCH_USE_QUEUED_SPINLOCKS
+	depends on SMP
+
+config ARCH_USE_QUEUED_RWLOCKS
+	bool
+
+config QUEUED_RWLOCKS
+	def_bool y if ARCH_USE_QUEUED_RWLOCKS
 	depends on SMP
kernel/futex.c +1 -1
index 2579e407ff67..55ca63ad9622 100644
@@ -2055,7 +2055,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
 {
 	/*
 	 * The task state is guaranteed to be set before another task can
-	 * wake it. set_current_state() is implemented using set_mb() and
+	 * wake it. set_current_state() is implemented using smp_store_mb() and
 	 * queue_me() calls spin_unlock() upon completion, both serializing
 	 * access to the hash list and forcing another memory barrier.
 	 */
kernel/locking/Makefile +2 -1
index de7a416cca2a..7dd5c9918e4c 100644
@@ -17,6 +17,7 @@ obj-$(CONFIG_SMP) += spinlock.o
 obj-$(CONFIG_LOCK_SPIN_ON_OWNER) += osq_lock.o
 obj-$(CONFIG_SMP) += lglock.o
 obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
+obj-$(CONFIG_QUEUED_SPINLOCKS) += qspinlock.o
 obj-$(CONFIG_RT_MUTEXES) += rtmutex.o
 obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o
 obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o
@@ -25,5 +26,5 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
 obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem-xadd.o
 obj-$(CONFIG_PERCPU_RWSEM) += percpu-rwsem.o
-obj-$(CONFIG_QUEUE_RWLOCK) += qrwlock.o
+obj-$(CONFIG_QUEUED_RWLOCKS) += qrwlock.o
 obj-$(CONFIG_LOCK_TORTURE_TEST) += locktorture.o
kernel/locking/lockdep.c +1 -2
index a0831e1b99f4..a61bb1d37a52 100644
@@ -4066,8 +4066,7 @@ void __init lockdep_info(void)
 
 #ifdef CONFIG_DEBUG_LOCKDEP
 	if (lockdep_init_error) {
-		printk("WARNING: lockdep init error! lock-%s was acquired"
-			"before lockdep_init\n", lock_init_error);
+		printk("WARNING: lockdep init error: lock '%s' was acquired before lockdep_init().\n", lock_init_error);
 		printk("Call stack leading to lockdep invocation was:\n");
 		print_stack_trace(&lockdep_init_trace, 0);
 	}
kernel/locking/mcs_spinlock.h +1 -0
index 75e114bdf3f2..fd91aaa4554c 100644
@@ -17,6 +17,7 @@
 struct mcs_spinlock {
 	struct mcs_spinlock *next;
 	int locked; /* 1 if lock acquired */
+	int count;  /* nesting count, see qspinlock.c */
 };
 
 #ifndef arch_mcs_spin_lock_contended
kernel/locking/qrwlock.c +25 -5
index f956ede7f90d..6c5da483966b 100644
@@ -1,5 +1,5 @@
 /*
- * Queue read/write lock
+ * Queued read/write locks
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,6 +22,26 @@
 #include <linux/hardirq.h>
 #include <asm/qrwlock.h>
 
+/*
+ * This internal data structure is used for optimizing access to some of
+ * the subfields within the atomic_t cnts.
+ */
+struct __qrwlock {
+	union {
+		atomic_t cnts;
+		struct {
+#ifdef __LITTLE_ENDIAN
+			u8 wmode;	/* Writer mode   */
+			u8 rcnts[3];	/* Reader counts */
+#else
+			u8 rcnts[3];	/* Reader counts */
+			u8 wmode;	/* Writer mode   */
+#endif
+		};
+	};
+	arch_spinlock_t	lock;
+};
+
 /**
  * rspin_until_writer_unlock - inc reader count & spin until writer is gone
  * @lock  : Pointer to queue rwlock structure
@@ -107,10 +127,10 @@ void queue_write_lock_slowpath(struct qrwlock *lock)
 	 * or wait for a previous writer to go away.
 	 */
 	for (;;) {
-		cnts = atomic_read(&lock->cnts);
-		if (!(cnts & _QW_WMASK) &&
-		    (atomic_cmpxchg(&lock->cnts, cnts,
-				    cnts | _QW_WAITING) == cnts))
+		struct __qrwlock *l = (struct __qrwlock *)lock;
+
+		if (!READ_ONCE(l->wmode) &&
+		   (cmpxchg(&l->wmode, 0, _QW_WAITING) == 0))
 			break;
 
 		cpu_relax_lowlatency();
kernel/locking/qspinlock.c new file +473 -0

473 lines not on this page · raw message

kernel/locking/qspinlock_paravirt.h new file +325 -0

325 lines not on this page · raw message

kernel/locking/rtmutex.c +10 -3
index b73279367087..5fa042be94d5 100644
@@ -70,10 +70,10 @@ static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
 }
 
 /*
- * We can speed up the acquire/release, if the architecture
- * supports cmpxchg and if there's no debugging state to be set up
+ * We can speed up the acquire/release, if there's no debugging state to be
+ * set up.
  */
-#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
+#ifndef CONFIG_DEBUG_RT_MUTEXES
 # define rt_mutex_cmpxchg(l,c,n)	(cmpxchg(&l->owner, c, n) == c)
 static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
 {
@@ -1441,10 +1441,17 @@ EXPORT_SYMBOL_GPL(rt_mutex_timed_lock);
  *
  * @lock:	the rt_mutex to be locked
  *
+ * This function can only be called in thread context. It's safe to
+ * call it from atomic regions, but not from hard interrupt or soft
+ * interrupt context.
+ *
  * Returns 1 on success and 0 on contention
  */
 int __sched rt_mutex_trylock(struct rt_mutex *lock)
 {
+	if (WARN_ON(in_irq() || in_nmi() || in_serving_softirq()))
+		return 0;
+
 	return rt_mutex_fasttrylock(lock, rt_mutex_slowtrylock);
 }
 EXPORT_SYMBOL_GPL(rt_mutex_trylock);
kernel/locking/rwsem-xadd.c +44 -0

62 lines not on this page · raw message

kernel/sched/wait.c +2 -2
index 852143a79f36..9bc82329eaad 100644
@@ -341,7 +341,7 @@ long wait_woken(wait_queue_t *wait, unsigned mode, long timeout)
 	 * condition being true _OR_ WQ_FLAG_WOKEN such that we will not miss
 	 * an event.
 	 */
-	set_mb(wait->flags, wait->flags & ~WQ_FLAG_WOKEN); /* B */
+	smp_store_mb(wait->flags, wait->flags & ~WQ_FLAG_WOKEN); /* B */
 
 	return timeout;
 }
@@ -354,7 +354,7 @@ int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
 	 * doesn't imply write barrier and the users expects write
 	 * barrier semantics on wakeup functions.  The following
 	 * smp_wmb() is equivalent to smp_wmb() in try_to_wake_up()
-	 * and is paired with set_mb() in wait_woken().
+	 * and is paired with smp_store_mb() in wait_woken().
 	 */
 	smp_wmb(); /* C */
 	wait->flags |= WQ_FLAG_WOKEN;

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/

#1 lore raw
Quoted 6 lines · Ingo Molnar

Linus,

Please pull the latest locking-core-for-linus git tree from:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking-core-for-linus

Quoted 7 lines

# HEAD: 68722101ec3a0e179408a13708dd020e04f54aab locking/lockdep: Remove hard coded array size dependency

The main changes are:

- 'qspinlock' support, enabled on x86: queued spinlocks - these are now the spinlock variant used by x86 as they outperform ticket spinlocks in every category. (Waiman Long)

Very interesting.

While rebasing http://www.kernelhub.org/?msg=737214&p=2

I found that indeed qspinlock improved the scalability issue by a big factor.

linux-4.1

lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 6977349, ops/sec 232578
6977349
lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 7326280, ops/sec 244209
7326280

Current Linus tree :

lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 15640802, ops/sec 521360
15640802
lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 15045022, ops/sec 501500
15045022

Adding fd_install() patch then :

lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 21471043, ops/sec 715701
21471043
lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 21068501, ops/sec 702283
21068501
#2 lore raw
Quoted 54 lines · Eric Dumazet
Quoted 8 lines · Ingo Molnar

Linus,

Please pull the latest locking-core-for-linus git tree from:

    git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking-core-for-linus

    # HEAD: 68722101ec3a0e179408a13708dd020e04f54aab locking/lockdep: Remove hard coded array size dependency
Quoted 5 lines

The main changes are:

- 'qspinlock' support, enabled on x86: queued spinlocks - these are now the spinlock variant used by x86 as they outperform ticket spinlocks in every category. (Waiman Long)

Very interesting.

While rebasing http://www.kernelhub.org/?msg=737214&p=2

I found that indeed qspinlock improved the scalability issue by a big factor.

linux-4.1

lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 6977349, ops/sec 232578
6977349
lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 7326280, ops/sec 244209
7326280

Current Linus tree :

lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 15640802, ops/sec 521360
15640802
lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 15045022, ops/sec 501500
15045022

Adding fd_install() patch then :

lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 21471043, ops/sec 715701
21471043
Quoted 4 lines
lpaa23:~# pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 21068501, ops/sec 702283
21068501

I am glad that the qspinlock patch helps. May I know what kind of machine (cpu type, # of sockets, etc) that you are running the test on? Usually the more sockets the machine has, the bigger the improvement you will see.

Cheers,
Longman

#3 lore raw
Quoted 4 lines · Waiman Long

I am glad that the qspinlock patch helps. May I know what kind of machine (cpu type, # of sockets, etc) that you are running the test on? Usually the more sockets the machine has, the bigger the improvement you will see.

This particular host had two Intel(R) Xeon(R) CPU E5-2696 v2 @ 2.50GHz

(12 cores per socket, total of 48 hyper threads)

Note that if pipebench uses 48 threads (instead of 16 as my previous mail did), there is almost no degradation.

lpaa23:~# ./pipebench -n 16
threads:16 sleep:30 pinned:1
total operations: 20228142, ops/sec 674271
20228142
lpaa23:~# ./pipebench -n 48
threads:48 sleep:30 pinned:1
total operations: 19763616, ops/sec 658787
19763616

Thanks