• Waiman Long's avatar
    locking/rwsem: Make handoff bit handling more consistent · d257cc8c
    Waiman Long authored
    There are some inconsistency in the way that the handoff bit is being
    handled in readers and writers that lead to a race condition.
    
    Firstly, when a queue head writer set the handoff bit, it will clear
    it when the writer is being killed or interrupted on its way out
    without acquiring the lock. That is not the case for a queue head
    reader. The handoff bit will simply be inherited by the next waiter.
    
    Secondly, in the out_nolock path of rwsem_down_read_slowpath(), both
    the waiter and handoff bits are cleared if the wait queue becomes
    empty.  For rwsem_down_write_slowpath(), however, the handoff bit is
    not checked and cleared if the wait queue is empty. This can
    potentially make the handoff bit set with empty wait queue.
    
    Worse, the situation in rwsem_down_write_slowpath() relies on wstate,
    a variable set outside of the critical section containing the ->count
    manipulation, this leads to race condition where RWSEM_FLAG_HANDOFF
    can be double subtracted, corrupting ->count.
    
    To make the handoff bit handling more consistent and robust, extract
    out handoff bit clearing code into the new rwsem_del_waiter() helper
    function. Also, completely eradicate wstate; always evaluate
    everything inside the same critical section.
    
    The common function will only use atomic_long_andnot() to clear bits
    when the wait queue is empty to avoid possible race condition.  If the
    first waiter with handoff bit set is killed or interrupted to exit the
    slowpath without acquiring the lock, the next waiter will inherit the
    handoff bit.
    
    While at it, simplify the trylock for loop in
    rwsem_down_write_slowpath() to make it easier to read.
    
    Fixes: 4f23dbc1 ("locking/rwsem: Implement lock handoff to prevent lock starvation")
    Reported-by: default avatarZhenhua Ma <mazhenhua@xiaomi.com>
    Suggested-by: default avatarPeter Zijlstra <peterz@infradead.org>
    Signed-off-by: default avatarWaiman Long <longman@redhat.com>
    Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
    Link: https://lkml.kernel.org/r/20211116012912.723980-1-longman@redhat.com
    d257cc8c
rwsem.c 44.3 KB