rwsem: skip initial trylock in rwsem_down_write_failed
authorMichel Lespinasse <walken@google.com>
Tue, 7 May 2013 13:45:57 +0000 (06:45 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 7 May 2013 14:20:16 +0000 (07:20 -0700)
We can skip the initial trylock in rwsem_down_write_failed() if there
are known active lockers already, thus saving one likely-to-fail
cmpxchg.

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>
lib/rwsem.c

index edf3d9ca670ef7889c81d6e9520a7ea5c6797d44..0d50e46d5b0c9bed7a607452615da6fececbec16 100644 (file)
@@ -216,14 +216,15 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
        /* wait until we successfully acquire the lock */
        set_task_state(tsk, TASK_UNINTERRUPTIBLE);
        while (true) {
-
-               /* Try acquiring the write lock. */
-               count = RWSEM_ACTIVE_WRITE_BIAS;
-               if (!list_is_singular(&sem->wait_list))
-                       count += RWSEM_WAITING_BIAS;
-               if (cmpxchg(&sem->count, RWSEM_WAITING_BIAS, count) ==
+               if (!(count & RWSEM_ACTIVE_MASK)) {
+                       /* Try acquiring the write lock. */
+                       count = RWSEM_ACTIVE_WRITE_BIAS;
+                       if (!list_is_singular(&sem->wait_list))
+                               count += RWSEM_WAITING_BIAS;
+                       if (cmpxchg(&sem->count, RWSEM_WAITING_BIAS, count) ==
                                                        RWSEM_WAITING_BIAS)
-                       break;
+                               break;
+               }
 
                raw_spin_unlock_irq(&sem->wait_lock);
 
@@ -231,7 +232,7 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
                do {
                        schedule();
                        set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-               } while (sem->count & RWSEM_ACTIVE_MASK);
+               } while ((count = sem->count) & RWSEM_ACTIVE_MASK);
 
                raw_spin_lock_irq(&sem->wait_lock);
        }