aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMichel Lespinasse <walken@google.com>2013-05-07 09:45:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-07 10:20:16 -0400
commit5ede972df1cd9294c82e9515949fd2103be81d7b (patch)
tree2c6df4c16fbe4430ea2723f2aec284105aab08db /lib
parented00f64346631dff035adfb9b0240daaa8b46c4e (diff)
rwsem: use cmpxchg for trying to steal write lock
Using rwsem_atomic_update to try stealing the write lock forced us to undo the adjustment in the failure path. We can have simpler and faster code by using cmpxchg instead. Signed-off-by: Michel Lespinasse <walken@google.com> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Acked-by: Davidlohr Bueso <davidlohr.bueso@hp.com> Acked-by: Rik van Riel <riel@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/rwsem.c26
1 files changed, 6 insertions, 20 deletions
diff --git a/lib/rwsem.c b/lib/rwsem.c
index 2360bf204098..64c2dc007be2 100644
--- a/lib/rwsem.c
+++ b/lib/rwsem.c
@@ -142,25 +142,6 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wake_type)
142 return sem; 142 return sem;
143} 143}
144 144
145/* Try to get write sem, caller holds sem->wait_lock: */
146static int try_get_writer_sem(struct rw_semaphore *sem)
147{
148 long oldcount, adjustment;
149
150 adjustment = RWSEM_ACTIVE_WRITE_BIAS;
151 if (list_is_singular(&sem->wait_list))
152 adjustment -= RWSEM_WAITING_BIAS;
153
154try_again_write:
155 oldcount = rwsem_atomic_update(adjustment, sem) - adjustment;
156 if (!(oldcount & RWSEM_ACTIVE_MASK))
157 return 1;
158 /* some one grabbed the sem already */
159 if (rwsem_atomic_update(-adjustment, sem) & RWSEM_ACTIVE_MASK)
160 return 0;
161 goto try_again_write;
162}
163
164/* 145/*
165 * wait for the read lock to be granted 146 * wait for the read lock to be granted
166 */ 147 */
@@ -236,7 +217,12 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
236 while (true) { 217 while (true) {
237 set_task_state(tsk, TASK_UNINTERRUPTIBLE); 218 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
238 219
239 if (try_get_writer_sem(sem)) 220 /* Try acquiring the write lock. */
221 count = RWSEM_ACTIVE_WRITE_BIAS;
222 if (!list_is_singular(&sem->wait_list))
223 count += RWSEM_WAITING_BIAS;
224 if (cmpxchg(&sem->count, RWSEM_WAITING_BIAS, count) ==
225 RWSEM_WAITING_BIAS)
240 break; 226 break;
241 227
242 raw_spin_unlock_irq(&sem->wait_lock); 228 raw_spin_unlock_irq(&sem->wait_lock);