• D
    xfs: xfs_check_page_type buffer checks need help · a49935f2
    Dave Chinner 提交于
    xfs_aops_discard_page() was introduced in the following commit:
    
      xfs: truncate delalloc extents when IO fails in writeback
    
    ... to clean up left over delalloc ranges after I/O failure in
    ->writepage(). generic/224 tests for this scenario and occasionally
    reproduces panics on sub-4k blocksize filesystems.
    
    The cause of this is failure to clean up the delalloc range on a
    page where the first buffer does not match one of the expected
    states of xfs_check_page_type(). If a buffer is not unwritten,
    delayed or dirty&mapped, xfs_check_page_type() stops and
    immediately returns 0.
    
    The stress test of generic/224 creates a scenario where the first
    several buffers of a page with delayed buffers are mapped & uptodate
    and some subsequent buffer is delayed. If the ->writepage() happens
    to fail for this page, xfs_aops_discard_page() incorrectly skips
    the entire page.
    
    This then causes later failures either when direct IO maps the range
    and finds the stale delayed buffer, or we evict the inode and find
    that the inode still has a delayed block reservation accounted to
    it.
    
    We can easily fix this xfs_aops_discard_page() failure by making
    xfs_check_page_type() check all buffers, but this breaks
    xfs_convert_page() more than it is already broken. Indeed,
    xfs_convert_page() wants xfs_check_page_type() to tell it if the
    first buffers on the pages are of a type that can be aggregated into
    the contiguous IO that is already being built.
    
    xfs_convert_page() should not be writing random buffers out of a
    page, but the current behaviour will cause it to do so if there are
    buffers that don't match the current specification on the page.
    Hence for xfs_convert_page() we need to:
    
    	a) return "not ok" if the first buffer on the page does not
    	match the specification provided to we don't write anything;
    	and
    	b) abort it's buffer-add-to-io loop the moment we come
    	across a buffer that does not match the specification.
    
    Hence we need to fix both xfs_check_page_type() and
    xfs_convert_page() to work correctly with pages that have mixed
    buffer types, whilst allowing xfs_aops_discard_page() to scan all
    buffers on the page for a type match.
    Reported-by: NBrian Foster <bfoster@redhat.com>
    Signed-off-by: NDave Chinner <dchinner@redhat.com>
    Reviewed-by: NChristoph Hellwig <hch@lst.de>
    Signed-off-by: NDave Chinner <david@fromorbit.com>
    a49935f2
xfs_aops.c 43.5 KB