On Fri, Aug 10, 2012 at 03:01:51PM -0300, Carlos Maiolino wrote:
> While xfs_buftarg_shrink() is freeing buffers from the dispose list (filled
> 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()
> 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
> *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
> 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
> 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: Carlos Maiolino <cmaiolino@xxxxxxxxxx>
Reviewed-by: Dave Chinner <dchinner@xxxxxxxxxx>