• Rik van Riel's avatar
    xfs: fix missed wakeup on l_flush_wait · cdea5459
    Rik van Riel authored
    The code in xlog_wait uses the spinlock to make adding the task to
    the wait queue, and setting the task state to UNINTERRUPTIBLE atomic
    with respect to the waker.
    
    Doing the wakeup after releasing the spinlock opens up the following
    race condition:
    
    Task 1					task 2
    add task to wait queue
    					wake up task
    set task state to UNINTERRUPTIBLE
    
    This issue was found through code inspection as a result of kworkers
    being observed stuck in UNINTERRUPTIBLE state with an empty
    wait queue. It is rare and largely unreproducable.
    
    Simply moving the spin_unlock to after the wake_up_all results
    in the waker not being able to see a task on the waitqueue before
    it has set its state to UNINTERRUPTIBLE.
    
    This bug dates back to the conversion of this code to generic
    waitqueue infrastructure from a counting semaphore back in 2008
    which didn't place the wakeups consistently w.r.t. to the relevant
    spin locks.
    
    [dchinner: Also fix a similar issue in the shutdown path on
    xc_commit_wait. Update commit log with more details of the issue.]
    
    Fixes: d748c623 ("[XFS] Convert l_flushsema to a sv_t")
    Reported-by: default avatarChris Mason <clm@fb.com>
    Signed-off-by: default avatarRik van Riel <riel@surriel.com>
    Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
    Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
    Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
    cdea5459
xfs_log.c 112 KB