On Sun, Apr 28, 2019 at 05:25:46PM -0400, Waiman Long wrote:

> +                     /*
> +                      * This waiter may have become first in the wait
> +                      * list after re-acquring the wait_lock. The
> +                      * rwsem_first_waiter() test in the main while
> +                      * loop below will correctly detect that. We do
> +                      * need to reload count to perform proper trylock
> +                      * and avoid missed wakeup.
> +                      */
> +                     count = atomic_long_read(&sem->count);
> +             }
>       } else {
>               count = atomic_long_add_return(RWSEM_FLAG_WAITERS, &sem->count);
>       }

I've been eyeing that count usage for the past few patches, and this
here makes me think we should get rid of it.

--- a/kernel/locking/rwsem.c
+++ b/kernel/locking/rwsem.c
@@ -400,13 +400,14 @@ static void __rwsem_mark_wake(struct rw_
  * If wstate is WRITER_HANDOFF, it will make sure that either the handoff
  * bit is set or the lock is acquired with handoff bit cleared.
  */
-static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem,
+static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
                                        enum writer_wait_state wstate)
 {
-       long new;
+       long count, new;
 
        lockdep_assert_held(&sem->wait_lock);
 
+       count = atomic_long_read(&sem->count);
        do {
                bool has_handoff = !!(count & RWSEM_FLAG_HANDOFF);
 
@@ -760,25 +761,16 @@ rwsem_down_write_slowpath(struct rw_sema
                        wake_up_q(&wake_q);
                        wake_q_init(&wake_q);   /* Used again, reinit */
                        raw_spin_lock_irq(&sem->wait_lock);
-                       /*
-                        * This waiter may have become first in the wait
-                        * list after re-acquring the wait_lock. The
-                        * rwsem_first_waiter() test in the main while
-                        * loop below will correctly detect that. We do
-                        * need to reload count to perform proper trylock
-                        * and avoid missed wakeup.
-                        */
-                       count = atomic_long_read(&sem->count);
                }
        } else {
-               count = atomic_long_add_return(RWSEM_FLAG_WAITERS, &sem->count);
+               atomic_long_or(RWSEM_FLAG_WAITERS, &sem->count);
        }
 
 wait:
        /* wait until we successfully acquire the lock */
        set_current_state(state);
        for (;;) {
-               if (rwsem_try_write_lock(count, sem, wstate))
+               if (rwsem_try_write_lock(sem, wstate))
                        break;
 
                raw_spin_unlock_irq(&sem->wait_lock);
@@ -819,7 +811,6 @@ rwsem_down_write_slowpath(struct rw_sema
                }
 
                raw_spin_lock_irq(&sem->wait_lock);
-               count = atomic_long_read(&sem->count);
        }
        __set_current_state(TASK_RUNNING);
        list_del(&waiter.list);

Reply via email to