• Brian Foster's avatar
    iomap: set page dirty after partial delalloc on mkwrite · 561295a3
    Brian Foster authored
    The iomap page fault mechanism currently dirties the associated page
    after the full block range of the page has been allocated. This
    leaves the page susceptible to delayed allocations without ever
    being set dirty on sub-page block sized filesystems.
    
    For example, consider a page fault on a page with one preexisting
    real (non-delalloc) block allocated in the middle of the page. The
    first iomap_apply() iteration performs delayed allocation on the
    range up to the preexisting block, the next iteration finds the
    preexisting block, and the last iteration attempts to perform
    delayed allocation on the range after the prexisting block to the
    end of the page. If the first allocation succeeds and the final
    allocation fails with -ENOSPC, iomap_apply() returns the error and
    iomap_page_mkwrite() fails to dirty the page having already
    performed partial delayed allocation. This eventually results in the
    page being invalidated without ever converting the delayed
    allocation to real blocks.
    
    This problem is reliably reproduced by generic/083 on XFS on ppc64
    systems (64k page size, 4k block size). It results in leaked
    delalloc blocks on inode reclaim, which triggers an assert failure
    in xfs_fs_destroy_inode() and filesystem accounting inconsistency.
    
    Move the set_page_dirty() call from iomap_page_mkwrite() to the
    actor callback, similar to how the buffer head implementation works.
    The actor callback is called iff ->iomap_begin() returns success, so
    ensures the page is dirtied as soon as possible after an allocation.
    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>
    561295a3
iomap.c 52.1 KB