diff options
author | Peter Zijlstra <peterz@infradead.org> | 2016-06-01 14:58:15 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-06-08 09:17:01 -0400 |
commit | 6428671bae97caa7040e24e79e969fd87908f4f3 (patch) | |
tree | 67549d91213b5fc3bb48a243ebfaf1ef3fc2b9a2 | |
parent | ddd0fa73c2b71c35de4fe7ae60a5f1a6cddc2cf0 (diff) |
locking/mutex: Optimize mutex_trylock() fast-path
A while back Viro posted a number of 'interesting' mutex_is_locked()
users on IRC, one of those was RCU.
RCU seems to use mutex_is_locked() to avoid doing mutex_trylock(), the
regular load before modify pattern.
While the use isn't wrong per se, its curious in that its needed at all,
mutex_trylock() should be good enough on its own to avoid the pointless
cacheline bounces.
So fix those and remove the mutex_is_locked() (ab)use from RCU.
Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Paul McKenney <paulmck@linux.vnet.ibm.com>
Acked-by: Davidlohr Bueso <dave@stgolabs.net>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Waiman Long <Waiman.Long@hpe.com>
Link: http://lkml.kernel.org/r/20160601185815.GW3190@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/ia64/include/asm/mutex.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/mutex.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/mutex_32.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/mutex_64.h | 6 | ||||
-rw-r--r-- | include/asm-generic/mutex-dec.h | 2 | ||||
-rw-r--r-- | include/asm-generic/mutex-xchg.h | 6 | ||||
-rw-r--r-- | kernel/rcu/tree.c | 1 |
7 files changed, 12 insertions, 9 deletions
diff --git a/arch/ia64/include/asm/mutex.h b/arch/ia64/include/asm/mutex.h index f41e66d65e31..28cb819e0ff9 100644 --- a/arch/ia64/include/asm/mutex.h +++ b/arch/ia64/include/asm/mutex.h | |||
@@ -82,7 +82,7 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) | |||
82 | static inline int | 82 | static inline int |
83 | __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) | 83 | __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) |
84 | { | 84 | { |
85 | if (cmpxchg_acq(count, 1, 0) == 1) | 85 | if (atomic_read(count) == 1 && cmpxchg_acq(count, 1, 0) == 1) |
86 | return 1; | 86 | return 1; |
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
diff --git a/arch/powerpc/include/asm/mutex.h b/arch/powerpc/include/asm/mutex.h index 127ab23e1f6c..078155fa1189 100644 --- a/arch/powerpc/include/asm/mutex.h +++ b/arch/powerpc/include/asm/mutex.h | |||
@@ -124,7 +124,7 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) | |||
124 | static inline int | 124 | static inline int |
125 | __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) | 125 | __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) |
126 | { | 126 | { |
127 | if (likely(__mutex_cmpxchg_lock(count, 1, 0) == 1)) | 127 | if (likely(atomic_read(count) == 1 && __mutex_cmpxchg_lock(count, 1, 0) == 1)) |
128 | return 1; | 128 | return 1; |
129 | return 0; | 129 | return 0; |
130 | } | 130 | } |
diff --git a/arch/x86/include/asm/mutex_32.h b/arch/x86/include/asm/mutex_32.h index 85e6cda45a02..e9355a84fc67 100644 --- a/arch/x86/include/asm/mutex_32.h +++ b/arch/x86/include/asm/mutex_32.h | |||
@@ -101,7 +101,7 @@ static inline int __mutex_fastpath_trylock(atomic_t *count, | |||
101 | int (*fail_fn)(atomic_t *)) | 101 | int (*fail_fn)(atomic_t *)) |
102 | { | 102 | { |
103 | /* cmpxchg because it never induces a false contention state. */ | 103 | /* cmpxchg because it never induces a false contention state. */ |
104 | if (likely(atomic_cmpxchg(count, 1, 0) == 1)) | 104 | if (likely(atomic_read(count) == 1 && atomic_cmpxchg(count, 1, 0) == 1)) |
105 | return 1; | 105 | return 1; |
106 | 106 | ||
107 | return 0; | 107 | return 0; |
diff --git a/arch/x86/include/asm/mutex_64.h b/arch/x86/include/asm/mutex_64.h index 07537a44216e..d9850758464e 100644 --- a/arch/x86/include/asm/mutex_64.h +++ b/arch/x86/include/asm/mutex_64.h | |||
@@ -118,10 +118,10 @@ do { \ | |||
118 | static inline int __mutex_fastpath_trylock(atomic_t *count, | 118 | static inline int __mutex_fastpath_trylock(atomic_t *count, |
119 | int (*fail_fn)(atomic_t *)) | 119 | int (*fail_fn)(atomic_t *)) |
120 | { | 120 | { |
121 | if (likely(atomic_cmpxchg(count, 1, 0) == 1)) | 121 | if (likely(atomic_read(count) == 1 && atomic_cmpxchg(count, 1, 0) == 1)) |
122 | return 1; | 122 | return 1; |
123 | else | 123 | |
124 | return 0; | 124 | return 0; |
125 | } | 125 | } |
126 | 126 | ||
127 | #endif /* _ASM_X86_MUTEX_64_H */ | 127 | #endif /* _ASM_X86_MUTEX_64_H */ |
diff --git a/include/asm-generic/mutex-dec.h b/include/asm-generic/mutex-dec.h index fd694cfd678a..c54829d3de37 100644 --- a/include/asm-generic/mutex-dec.h +++ b/include/asm-generic/mutex-dec.h | |||
@@ -80,7 +80,7 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) | |||
80 | static inline int | 80 | static inline int |
81 | __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) | 81 | __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) |
82 | { | 82 | { |
83 | if (likely(atomic_cmpxchg_acquire(count, 1, 0) == 1)) | 83 | if (likely(atomic_read(count) == 1 && atomic_cmpxchg_acquire(count, 1, 0) == 1)) |
84 | return 1; | 84 | return 1; |
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
diff --git a/include/asm-generic/mutex-xchg.h b/include/asm-generic/mutex-xchg.h index a6b4a7bd6ac9..3269ec4e195f 100644 --- a/include/asm-generic/mutex-xchg.h +++ b/include/asm-generic/mutex-xchg.h | |||
@@ -91,8 +91,12 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) | |||
91 | static inline int | 91 | static inline int |
92 | __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) | 92 | __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) |
93 | { | 93 | { |
94 | int prev = atomic_xchg_acquire(count, 0); | 94 | int prev; |
95 | 95 | ||
96 | if (atomic_read(count) != 1) | ||
97 | return 0; | ||
98 | |||
99 | prev = atomic_xchg_acquire(count, 0); | ||
96 | if (unlikely(prev < 0)) { | 100 | if (unlikely(prev < 0)) { |
97 | /* | 101 | /* |
98 | * The lock was marked contended so we must restore that | 102 | * The lock was marked contended so we must restore that |
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index c7f1bc4f817c..b7326893221f 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
@@ -3681,7 +3681,6 @@ static bool exp_funnel_lock(struct rcu_state *rsp, unsigned long s) | |||
3681 | if (ULONG_CMP_LT(READ_ONCE(rnp->exp_seq_rq), s) && | 3681 | if (ULONG_CMP_LT(READ_ONCE(rnp->exp_seq_rq), s) && |
3682 | (rnp == rnp_root || | 3682 | (rnp == rnp_root || |
3683 | ULONG_CMP_LT(READ_ONCE(rnp_root->exp_seq_rq), s)) && | 3683 | ULONG_CMP_LT(READ_ONCE(rnp_root->exp_seq_rq), s)) && |
3684 | !mutex_is_locked(&rsp->exp_mutex) && | ||
3685 | mutex_trylock(&rsp->exp_mutex)) | 3684 | mutex_trylock(&rsp->exp_mutex)) |
3686 | goto fastpath; | 3685 | goto fastpath; |
3687 | 3686 | ||