locking changes for v4.6
Subsystems (9)
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: 38460a2178d225b39ade5ac66586c3733391cf86 locking/csd_lock: Use smp_cond_acquire() in csd_lock_wait()
Various updates:
- Futex scalability improvements: remove page lock use for shared futex get_futex_key(), which speeds up 'perf bench futex hash' benchmarks by over 40% on a 60-core Westmere. This makes anon-mem shared futexes perform close to private futexes. (Mel Gorman)
- lockdep hash collision detection and fix (Alfredo Alvarez Fernandez)
- lockdep testing enhancements (Alfredo Alvarez Fernandez)
- robustify lockdep init by using hlists (Andrew Morton, Andrey Ryabinin)
- mutex and csd_lock micro-optimizations (Davidlohr Bueso)
- small x86 barriers tweaks (Michael S. Tsirkin)
- qspinlock updates (Waiman Long)
Thanks,
Ingo
------------------>
Alfredo Alvarez Fernandez (3):
tools/lib/lockdep: Add userspace version of READ_ONCE() tools/lib/lockdep: Add tests for AA and ABBA locking locking/lockdep: Prevent chain_key collisions
Andrew Morton (1):
locking/lockdep: Convert hash tables to hlists
Andrey Ryabinin (1):
locking/lockdep: Eliminate lockdep_init()
Arnd Bergmann (1):
locking/static_keys: Avoid nested functions
Dan Streetman (1):
locking/qspinlock: Move __ARCH_SPIN_LOCK_UNLOCKED to qspinlock_types.h
Davidlohr Bueso (4):
futex: Rename barrier references in ordering guarantees locking/mutex: Allow next waiter lockless wakeup locking/csd_lock: Explicitly inline csd_lock*() helpers locking/csd_lock: Use smp_cond_acquire() in csd_lock_wait()
Ingo Molnar (3):
tools/lib/lockdep: Fix the build on recent kernels tools/lib/lockdep: Fix link creation warning locking/lockdep: Detect chain_key collisions
Jianyu Zhan (1):
futex: Replace barrier() in unqueue_me() with READ_ONCE()
Konrad Rzeszutek Wilk (1):
locking/atomics: Update comment about READ_ONCE() and structures
Mel Gorman (1):
futex: Remove requirement for lock_page() in get_futex_key()
Michael S. Tsirkin (4):
locking/x86: Add cc clobber for ADDL locking/x86: Drop a comment left over from X86_OOSTORE locking/x86: Tweak the comment about use of wmb() for IO locking/x86: Use mb() around clflush()
Peter Zijlstra (1):
locking/mcs: Fix mcs_spin_lock() ordering
Waiman Long (3):
locking/pvqspinlock: Move lock stealing count tracking code into pv_queued_spin_steal_lock() locking/qspinlock: Use smp_cond_acquire() in pending code locking/pvqspinlock: Enable slowpath locking count tracking
arch/c6x/kernel/setup.c | 2 - arch/microblaze/kernel/setup.c | 2 - arch/powerpc/kernel/setup_32.c | 2 - arch/powerpc/kernel/setup_64.c | 3 - arch/s390/kernel/early.c | 1 - arch/sparc/kernel/head_64.S | 8 -- arch/x86/include/asm/barrier.h | 15 ++- arch/x86/kernel/process.c | 4 +- arch/x86/lguest/boot.c | 6 -- include/asm-generic/qspinlock.h | 5 - include/asm-generic/qspinlock_types.h | 5 + include/linux/compiler.h | 5 +- include/linux/lockdep.h | 2 - init/main.c | 5 - kernel/futex.c | 139 +++++++++++++++++++++----- kernel/locking/lockdep.c | 132 +++++++++++------------- kernel/locking/mcs_spinlock.h | 8 +- kernel/locking/mutex.c | 5 +- kernel/locking/qspinlock.c | 7 +- kernel/locking/qspinlock_paravirt.h | 21 ++-- kernel/locking/qspinlock_stat.h | 16 +-- kernel/smp.c | 9 +- lib/test_static_keys.c | 62 ++++++++---- tools/lib/lockdep/Makefile | 2 +- tools/lib/lockdep/common.c | 5 - tools/lib/lockdep/include/liblockdep/common.h | 1 - tools/lib/lockdep/lockdep.c | 6 ++ tools/lib/lockdep/preload.c | 2 - tools/lib/lockdep/tests/AA.c | 8 +- tools/lib/lockdep/tests/ABA.c | 13 +++ tools/lib/lockdep/tests/ABBA_2threads.c | 46 +++++++++ tools/lib/lockdep/uinclude/linux/compiler.h | 1 + 32 files changed, 334 insertions(+), 214 deletions(-) create mode 100644 tools/lib/lockdep/tests/ABA.c create mode 100644 tools/lib/lockdep/tests/ABBA_2threads.c
arch/c6x/kernel/setup.c +0 -2
@@ -281,8 +281,6 @@ notrace void __init machine_init(unsigned long dt_ptr)*/ set_ist (_vectors_start); -lockdep_init (); -/* * dtb is passed in from bootloader. * fdt is linked in blob.
arch/microblaze/kernel/setup.c +0 -2
@@ -130,8 +130,6 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,memset (__bss_start,0 , __bss_stop-__bss_start);memset (_ssbss,0 , _esbss-_ssbss); -lockdep_init (); -/* initialize device tree for usage in early_printk */ early_init_devtree (_fdt_start);
arch/powerpc/kernel/setup_32.c +0 -2
@@ -114,8 +114,6 @@ extern unsigned int memset_nocache_branch; /* Insn to be replaced by NOP */ notrace void __init machine_init(u64 dt_ptr) { -lockdep_init (); -/* Enable early debugging if any specified (see udbg.h) */ udbg_early_init ();
arch/powerpc/kernel/setup_64.c +0 -3
@@ -255,9 +255,6 @@ void __init early_setup(unsigned long dt_ptr)setup_paca (&boot_paca);fixup_boot_paca (); -/* Initialize lockdep early or else spinlocks will blow */ -lockdep_init (); -/* -------- printk is now safe to use ------- */ /* Enable early debugging if any specified (see udbg.h) */
arch/s390/kernel/early.c +0 -1
@@ -448,7 +448,6 @@ void __init startup_init(void)rescue_initrd ();clear_bss_section ();init_kernel_storage_key (); -lockdep_init ();lockdep_off ();setup_lowcore_early ();setup_facility_list ();
arch/sparc/kernel/head_64.S +0 -8
@@ -696,14 +696,6 @@ call __bzero sub %o1, %o0, %o1 -#ifdef CONFIG_LOCKDEP - /* We have this call this super early, as even prom_init can grab - * spinlocks and thus call into the lockdep code. - */ - call lockdep_init - nop -#endif - call prom_init mov %l7, %o0 ! OpenPROM cif handler
arch/x86/include/asm/barrier.h +7 -8
@@ -6,18 +6,17 @@/* * Force strict CPU ordering. -* And yes, this is required on UP too when we're talking +* And yes, this might be required on UP too when we're talking * to devices. */ #ifdef CONFIG_X86_32 -/* -* Some non-Intel clones support out of order store. wmb() ceases to be a -* nop for these. -*/ -#define mb () alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2) -#define rmb () alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2) -#define wmb () alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM) +#define mb () asm volatile(ALTERNATIVE("lock; addl $0,0(%%esp)", "mfence", \ + X86_FEATURE_XMM2) ::: "memory", "cc") +#define rmb () asm volatile(ALTERNATIVE("lock; addl $0,0(%%esp)", "lfence", \ + X86_FEATURE_XMM2) ::: "memory", "cc") +#define wmb () asm volatile(ALTERNATIVE("lock; addl $0,0(%%esp)", "sfence", \ + X86_FEATURE_XMM2) ::: "memory", "cc")#else #define mb () asm volatile("mfence":::"memory")#define rmb () asm volatile("lfence":::"memory")
arch/x86/kernel/process.c +2 -2
@@ -418,9 +418,9 @@ static void mwait_idle(void)if (!current_set_polling_and_test ()) {trace_cpu_idle_rcuidle (1 ,smp_processor_id ());if (this_cpu_has (X86_BUG_CLFLUSH_MONITOR )) { -smp_mb ();/* quirk */ +mb ();/* quirk */ clflush ((void *)¤t_thread_info ()->flags); -smp_mb ();/* quirk */ +mb ();/* quirk */ }__monitor ((void *)¤t_thread_info ()->flags,0 ,0 );
arch/x86/lguest/boot.c +0 -6
@@ -1520,12 +1520,6 @@ __init void lguest_init(void)*/ reserve_top_address (lguest_data.reserve_mem); -/* -* If we don't initialize the lock dependency checker now, it crashes -* atomic_notifier_chain_register, then paravirt_disable_iospace. -*/ -lockdep_init (); -/* Hook in our special panic hypercall code. */ atomic_notifier_chain_register (&panic_notifier_list, &paniced);
include/asm-generic/qspinlock.h +0 -5
@@ -120,11 +120,6 @@ static __always_inline bool virt_spin_lock(struct qspinlock *lock)#endif /* -* Initializier -*/ -#define __ARCH_SPIN_LOCK_UNLOCKED { ATOMIC_INIT(0) } - -/* * Remapping spinlock architecture specific functions to the corresponding * queued spinlock functions. */
include/asm-generic/qspinlock_types.h +5 -0
@@ -33,6 +33,11 @@ typedef struct qspinlock { } arch_spinlock_t;/* +* Initializier +*/ +#define __ARCH_SPIN_LOCK_UNLOCKED { ATOMIC_INIT(0) } + +/* * Bitfields in the atomic value: * * When NR_CPUS < 16K
include/linux/compiler.h +3 -2
@@ -263,8 +263,9 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s* In contrast to ACCESS_ONCE these two macros will also work on aggregate * data types like structs or unions. If the size of the accessed data * type exceeds the word size of the machine (e.g., 32 bits or 64 bits) -* READ_ONCE() and WRITE_ONCE() will fall back to memcpy and print a -* compile-time warning. +* READ_ONCE() and WRITE_ONCE() will fall back to memcpy(). There's at +* least two memcpy()s: one for the __builtin_memcpy() and then one for +* the macro doing the copy of variable - '__u' allocated on the stack. * * Their two major use cases are: (1) Mediating communication between * process-level code and irq/NMI handlers, all running on the same CPU,
include/linux/lockdep.h +0 -2
@@ -261,7 +261,6 @@ struct held_lock {/* * Initialization, self-test and debugging-output methods: */ -extern void lockdep_init (void );extern void lockdep_info (void );extern void lockdep_reset (void );extern void lockdep_reset_lock (struct lockdep_map *lock);
@@ -392,7 +391,6 @@ static inline void lockdep_on(void)# define lockdep_set_current_reclaim_state (g) do { } while (0)# define lockdep_clear_current_reclaim_state () do { } while (0)# define lockdep_trace_alloc (g) do { } while (0) -# define lockdep_init () do { } while (0)# define lockdep_info () do { } while (0)# define lockdep_init_map (lock, name, key, sub) \ do { (void)(name); (void)(key); } while (0)
init/main.c +0 -5
@@ -499,11 +499,6 @@ asmlinkage __visible void __init start_kernel(void)char *command_line;char *after_dashes; -/* -* Need to run as early as possible, to initialize the -* lockdep hash: -*/ -lockdep_init ();set_task_stack_end_magic (&init_task);smp_setup_processor_id ();debug_objects_early_init ();
kernel/futex.c +113 -26
217 lines not on this page · raw message
kernel/locking/lockdep.c +57 -75
227 lines not on this page · raw message
kernel/locking/mcs_spinlock.h +7 -1
@@ -67,7 +67,13 @@ void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node) node->locked =0 ; node->next =NULL ; - prev =xchg_acquire (lock, node); +/* +* We rely on the full barrier with global transitivity implied by the +* below xchg() to order the initialization stores above against any +* observation of @node. And to provide the ACQUIRE ordering associated +* with a LOCK primitive. +*/ + prev =xchg (lock, node);if (likely (prev ==NULL )) {/* * Lock acquired, don't need to set node->locked to 1. Threads
kernel/locking/mutex.c +3 -2
@@ -716,6 +716,7 @@ static inline void __mutex_unlock_common_slowpath(struct mutex *lock, int nested) {unsigned long flags; +WAKE_Q (wake_q);/* * As a performance measurement, release the lock before doing other
@@ -743,11 +744,11 @@ __mutex_unlock_common_slowpath(struct mutex *lock, int nested) struct mutex_waiter, list);debug_mutex_wake_waiter (lock, waiter); - -wake_up_process (waiter->task); +wake_q_add (&wake_q, waiter->task); }spin_unlock_mutex (&lock->wait_lock, flags); +wake_up_q (&wake_q); }/*
kernel/locking/qspinlock.c +3 -4
@@ -358,8 +358,7 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)* sequentiality; this is because not all clear_pending_set_locked() * implementations imply full barriers. */ -while ((val =smp_load_acquire (&lock->val.counter)) & _Q_LOCKED_MASK) -cpu_relax (); +smp_cond_acquire (!(atomic_read (&lock->val) & _Q_LOCKED_MASK));/* * take ownership and clear the pending bit.
@@ -435,7 +434,7 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)* * The PV pv_wait_head_or_lock function, if active, will acquire * the lock and return a non-zero value. So we have to skip the -* smp_load_acquire() call. As the next PV queue head hasn't been +* smp_cond_acquire() call. As the next PV queue head hasn't been * designated yet, there is no way for the locked value to become * _Q_SLOW_VAL. So both the set_locked() and the * atomic_cmpxchg_relaxed() calls will be safe.
@@ -466,7 +465,7 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)break ; }/* -* The smp_load_acquire() call above has provided the necessary +* The smp_cond_acquire() call above has provided the necessary * acquire semantics required for locking. At most two * iterations of this loop may be ran. */
kernel/locking/qspinlock_paravirt.h +14 -7
@@ -55,6 +55,11 @@ struct pv_node { };/* +* Include queued spinlock statistics code +*/ +#include "qspinlock_stat.h" + +/* * By replacing the regular queued_spin_trylock() with the function below, * it will be called once when a lock waiter enter the PV slowpath before * being queued. By allowing one lock stealing attempt here when the pending
@@ -65,9 +70,11 @@ struct pv_node {static inline bool pv_queued_spin_steal_lock (struct qspinlock *lock) {struct __qspinlock *l = (void *)lock; +int ret = !(atomic_read (&lock->val) & _Q_LOCKED_PENDING_MASK) && + (cmpxchg (&l->locked,0 , _Q_LOCKED_VAL) ==0 ); -return !(atomic_read (&lock->val) & _Q_LOCKED_PENDING_MASK) && - (cmpxchg (&l->locked,0 , _Q_LOCKED_VAL) ==0 ); +qstat_inc (qstat_pv_lock_stealing, ret); +return ret; }/*
@@ -138,11 +145,6 @@ static __always_inline int trylock_clear_pending(struct qspinlock *lock)#endif /* _Q_PENDING_BITS == 8 */ /* -* Include queued spinlock statistics code -*/ -#include "qspinlock_stat.h" - -/* * Lock and MCS node addresses hash table for fast lookup * * Hashing is done on a per-cacheline basis to minimize the need to access
@@ -398,6 +400,11 @@ pv_wait_head_or_lock(struct qspinlock *lock, struct mcs_spinlock *node)if (READ_ONCE (pn->state) == vcpu_hashed) lp = (struct qspinlock **)1 ; +/* +* Tracking # of slowpath locking operations +*/ +qstat_inc (qstat_pv_lock_slowpath, true); +for (;; waitcnt++) {/* * Set correct vCPU state to be used by queue node wait-early
kernel/locking/qspinlock_stat.h +3 -13
@@ -22,6 +22,7 @@* pv_kick_wake - # of vCPU kicks used for computing pv_latency_wake * pv_latency_kick - average latency (ns) of vCPU kick operation * pv_latency_wake - average latency (ns) from vCPU kick to wakeup +* pv_lock_slowpath - # of locking operations via the slowpath * pv_lock_stealing - # of lock stealing operations * pv_spurious_wakeup - # of spurious wakeups * pv_wait_again - # of vCPU wait's that happened after a vCPU kick
@@ -45,6 +46,7 @@ enum qlock_stats { qstat_pv_kick_wake, qstat_pv_latency_kick, qstat_pv_latency_wake, + qstat_pv_lock_slowpath, qstat_pv_lock_stealing, qstat_pv_spurious_wakeup, qstat_pv_wait_again,
@@ -70,6 +72,7 @@ static const char * const qstat_names[qstat_num + 1] = { [qstat_pv_spurious_wakeup] = "pv_spurious_wakeup", [qstat_pv_latency_kick] = "pv_latency_kick", [qstat_pv_latency_wake] = "pv_latency_wake", + [qstat_pv_lock_slowpath] = "pv_lock_slowpath", [qstat_pv_lock_stealing] = "pv_lock_stealing", [qstat_pv_wait_again] = "pv_wait_again", [qstat_pv_wait_early] = "pv_wait_early",
@@ -279,19 +282,6 @@ static inline void __pv_wait(u8 *ptr, u8 val)#define pv_kick (c) __pv_kick(c)#define pv_wait (p, v) __pv_wait(p, v) -/* -* PV unfair trylock count tracking function -*/ -static inline int qstat_spin_steal_lock (struct qspinlock *lock) -{ -int ret =pv_queued_spin_steal_lock (lock); - -qstat_inc (qstat_pv_lock_stealing, ret); -return ret; -} -#undef queued_spin_trylock -#define queued_spin_trylock (l) qstat_spin_steal_lock(l) -#else /* CONFIG_QUEUED_LOCK_STAT */ static inline void qstat_inc (enum qlock_stats stat,bool cond) { }
kernel/smp.c +4 -5
@@ -105,13 +105,12 @@ void __init call_function_init(void)* previous function call. For multi-cpu calls its even more interesting * as we'll have to ensure no other cpu is observing our csd. */ -static void csd_lock_wait (struct call_single_data *csd) +static __always_inline void csd_lock_wait(struct call_single_data *csd) { -while (smp_load_acquire (&csd->flags) &CSD_FLAG_LOCK ) -cpu_relax (); +smp_cond_acquire (!(csd->flags &CSD_FLAG_LOCK )); } -static void csd_lock (struct call_single_data *csd) +static __always_inline void csd_lock(struct call_single_data *csd) {csd_lock_wait (csd); csd->flags |=CSD_FLAG_LOCK ;
@@ -124,7 +123,7 @@ static void csd_lock(struct call_single_data *csd)smp_wmb (); } -static void csd_unlock (struct call_single_data *csd) +static __always_inline void csd_unlock(struct call_single_data *csd) {WARN_ON (!(csd->flags &CSD_FLAG_LOCK ));
lib/test_static_keys.c +42 -20
151 lines not on this page · raw message
tools/lib/lockdep/Makefile +1 -1
@@ -100,7 +100,7 @@ include $(srctree)/tools/build/Makefile.include do_compile_shared_library = \ ($(print_shared_lib_compile) \ - $(CC) --shared $^ -o $@ -lpthread -ldl -Wl,-soname='"$@"';$(shell ln -s $@ liblockdep.so)) + $(CC) --shared $^ -o $@ -lpthread -ldl -Wl,-soname='"$@"';$(shell ln -sf $@ liblockdep.so)) do_build_static_lib = \ ($(print_static_lib_build) \
tools/lib/lockdep/common.c +0 -5
@@ -11,11 +11,6 @@ static __thread struct task_struct current_obj;bool debug_locks = true;bool debug_locks_silent; -__attribute__((constructor))static void liblockdep_init (void ) -{ -lockdep_init (); -} - __attribute__((destructor))static void liblockdep_exit (void ) {debug_check_no_locks_held ();
tools/lib/lockdep/include/liblockdep/common.h +0 -1
@@ -44,7 +44,6 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,void lock_release (struct lockdep_map *lock,int nested,unsigned long ip);extern void debug_check_no_locks_freed (const void *from,unsigned long len); -extern void lockdep_init (void );#define STATIC_LOCKDEP_MAP_INIT (_name, _key) \ { .name = (_name), .key = (void *)(_key), }
tools/lib/lockdep/lockdep.c +6 -0
@@ -1,2 +1,8 @@#include <linux/lockdep.h> + +/* Trivial API wrappers, we don't (yet) have RCU in user-space: */ +#define hlist_for_each_entry_rcu hlist_for_each_entry +#define hlist_add_head_rcu hlist_add_head +#define hlist_del_rcu hlist_del +#include "../../../kernel/locking/lockdep.c"
tools/lib/lockdep/preload.c +0 -2
@@ -439,7 +439,5 @@ __attribute__((constructor)) static void init_preload(void) ll_pthread_rwlock_unlock =dlsym (RTLD_NEXT ,"pthread_rwlock_unlock" );#endif -lockdep_init (); - __init_state = done; }
tools/lib/lockdep/tests/AA.c +4 -4
@@ -1,13 +1,13 @@#include <liblockdep/mutex.h> -void main (void ) +int main (void ) { -pthread_mutex_t a, b; +pthread_mutex_t a;pthread_mutex_init (&a,NULL ); -pthread_mutex_init (&b,NULL );pthread_mutex_lock (&a); -pthread_mutex_lock (&b);pthread_mutex_lock (&a); + +return 0 ; }
tools/lib/lockdep/tests/ABA.c new file +13 -0
@@ -0,0 +1,13 @@ +#include <liblockdep/mutex.h> + +void main (void ) +{ +pthread_mutex_t a, b; + +pthread_mutex_init (&a,NULL ); +pthread_mutex_init (&b,NULL ); + +pthread_mutex_lock (&a); +pthread_mutex_lock (&b); +pthread_mutex_lock (&a); +}
tools/lib/lockdep/tests/ABBA_2threads.c new file +46 -0
46 lines not on this page · raw message
tools/lib/lockdep/uinclude/linux/compiler.h +1 -0
@@ -3,6 +3,7 @@#define __used __attribute__((__unused__))#define unlikely +#define READ_ONCE (x) (x)#define WRITE_ONCE (x, val) x=(val)#define RCU_INIT_POINTER (p, v) p=(v)