• Filipe Manana's avatar
    Btrfs: fix hole extent items with a zero size after range cloning · 147271e3
    Filipe Manana authored
    Normally when cloning a file range if we find an implicit hole at the end
    of the range we assume it is because the NO_HOLES feature is enabled.
    However that is not always the case. One well known case [1] is when we
    have a power failure after mixing buffered and direct IO writes against
    the same file.
    
    In such cases we need to punch a hole in the destination file, and if
    the NO_HOLES feature is not enabled, we need to insert explicit file
    extent items to represent the hole. After commit 690a5dbf
    ("Btrfs: fix ENOSPC errors, leading to transaction aborts, when cloning
    extents"), we started to insert file extent items representing the hole
    with an item size of 0, which is invalid and should be 53 bytes (the size
    of a btrfs_file_extent_item structure), resulting in all sorts of
    corruptions and invalid memory accesses. This is detected by the tree
    checker when we attempt to write a leaf to disk.
    
    The problem can be sporadically triggered by test case generic/561 from
    fstests. That test case does not exercise power failure and creates a new
    filesystem when it starts, so it does not use a filesystem created by any
    previous test that tests power failure. However the test does both
    buffered and direct IO writes (through fsstress) and it's precisely that
    which is creating the implicit holes in files. That happens even before
    the commit mentioned earlier. I need to investigate why we get those
    implicit holes to check if there is a real problem or not. For now this
    change fixes the regression of introducing file extent items with an item
    size of 0 bytes.
    
    Fix the issue by calling btrfs_punch_hole_range() without passing a
    btrfs_clone_extent_info structure, which ensures file extent items are
    inserted to represent the hole with a correct item size. We were passing
    a btrfs_clone_extent_info with a value of 0 for its 'item_size' field,
    which was causing the insertion of file extent items with an item size
    of 0.
    
    [1] https://www.spinics.net/lists/linux-btrfs/msg75350.htmlReported-by: default avatarDavid Sterba <dsterba@suse.com>
    Fixes: 690a5dbf ("Btrfs: fix ENOSPC errors, leading to transaction aborts, when cloning extents")
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    147271e3
ioctl.c 137 KB