• Carlos Maiolino's avatar
    xfs: fix race while discarding buffers [V4] · 6fb8a90a
    Carlos Maiolino authored
    While xfs_buftarg_shrink() is freeing buffers from the dispose list (filled with
    buffers from lru list), there is a possibility to have xfs_buf_stale() racing
    with it, and removing buffers from dispose list before xfs_buftarg_shrink() does
    it.
    
    This happens because xfs_buftarg_shrink() handle the dispose list without
    locking and the test condition in xfs_buf_stale() checks for the buffer being in
    *any* list:
    
    if (!list_empty(&bp->b_lru))
    
    If the buffer happens to be on dispose list, this causes the buffer counter of
    lru list (btp->bt_lru_nr) to be decremented twice (once in xfs_buftarg_shrink()
    and another in xfs_buf_stale()) causing a wrong account usage of the lru list.
    
    This may cause xfs_buftarg_shrink() to return a wrong value to the memory
    shrinker shrink_slab(), and such account error may also cause an underflowed
    value to be returned; since the counter is lower than the current number of
    items in the lru list, a decrement may happen when the counter is 0, causing
    an underflow on the counter.
    
    The fix uses a new flag field (and a new buffer flag) to serialize buffer
    handling during the shrink process. The new flag field has been designed to use
    btp->bt_lru_lock/unlock instead of xfs_buf_lock/unlock mechanism.
    
    dchinner, sandeen, aquini and aris also deserve credits for this.
    Signed-off-by: default avatarCarlos Maiolino <cmaiolino@redhat.com>
    Reviewed-by: default avatarBen Myers <bpm@sgi.com>
    Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
    Signed-off-by: default avatarBen Myers <bpm@sgi.com>
    6fb8a90a
xfs_buf.c 39.5 KB