• Brian Foster's avatar
    xfs: restore buffer_head unwritten bit on ioend cancel · 07d08681
    Brian Foster authored
    xfs_vm_writepage() walks each buffer_head on the page, maps to the block
    on disk and attaches to a running ioend structure that represents the
    I/O submission. A new ioend is created when the type of I/O (unwritten,
    delayed allocation or overwrite) required for a particular buffer_head
    differs from the previous. If a buffer_head is a delalloc or unwritten
    buffer, the associated bits are cleared by xfs_map_at_offset() once the
    buffer_head is added to the ioend.
    
    The process of mapping each buffer_head occurs in xfs_map_blocks() and
    acquires the ilock in blocking or non-blocking mode, depending on the
    type of writeback in progress. If the lock cannot be acquired for
    non-blocking writeback, we cancel the ioend, redirty the page and
    return. Writeback will revisit the page at some later point.
    
    Note that we acquire the ilock for each buffer on the page. Therefore
    during non-blocking writeback, it is possible to add an unwritten buffer
    to the ioend, clear the unwritten state, fail to acquire the ilock when
    mapping a subsequent buffer and cancel the ioend. If this occurs, the
    unwritten status of the buffer sitting in the ioend has been lost. The
    page will eventually hit writeback again, but xfs_vm_writepage() submits
    overwrite I/O instead of unwritten I/O and does not perform unwritten
    extent conversion at I/O completion. This leads to data corruption
    because unwritten extents are treated as holes on reads and zeroes are
    returned instead of reading from disk.
    
    Modify xfs_cancel_ioend() to restore the buffer unwritten bit for ioends
    of type XFS_IO_UNWRITTEN. This ensures that unwritten extent conversion
    occurs once the page is eventually written back.
    Signed-off-by: default avatarBrian Foster <bfoster@redhat.com>
    Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
    Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
    07d08681
xfs_aops.c 46.8 KB