diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 2a18a5f9c68e..00db8e10222a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2884,7 +2884,9 @@ static int btrfs_zero_range(struct inode *inode, u64 alloc_end = round_up(offset + len, sectorsize); u64 bytes_to_reserve = 0; bool space_reserved = false; - bool punch_hole = false; + struct extent_state *cached_state = NULL; + u64 lockstart; + u64 lockend; inode_dio_wait(inode); @@ -2945,11 +2947,15 @@ static int btrfs_zero_range(struct inode *inode, len, mode); goto out; } - if (len < sectorsize && em->block_start != EXTENT_MAP_HOLE) - punch_hole = true; + + if (len < sectorsize && em->block_start != EXTENT_MAP_HOLE) { + ret = btrfs_truncate_block(inode, offset, len, 0); + free_extent_map(em); + return ret; + } + free_extent_map(em); - if (punch_hole) - goto punch_hole; + alloc_start = round_down(offset, sectorsize); alloc_end = alloc_start + sectorsize; goto reserve_space; @@ -2994,10 +3000,9 @@ static int btrfs_zero_range(struct inode *inode, } reserve_space: - if (alloc_start < alloc_end) - bytes_to_reserve += alloc_end - alloc_start; + if (alloc_start < alloc_end) { + bytes_to_reserve = alloc_end - alloc_start; - if (!punch_hole && bytes_to_reserve > 0) { ret = btrfs_alloc_data_chunk_ondemand(BTRFS_I(inode), bytes_to_reserve); if (ret < 0) @@ -3009,31 +3014,22 @@ static int btrfs_zero_range(struct inode *inode, goto out; } -punch_hole: - if (punch_hole) { - ret = btrfs_punch_hole(inode, offset, len, false); - if (ret) - goto out; - ret = btrfs_zero_range_update_isize(inode, offset, len, mode); - } else { - struct extent_state *cached_state = NULL; - const u64 lockstart = alloc_start; - const u64 lockend = alloc_end - 1; + lockstart = alloc_start; + lockend = alloc_end - 1; + ret = btrfs_punch_hole_lock_range(inode, lockstart, lockend, + &cached_state); + if (ret) + goto out; + ret = btrfs_prealloc_file_range(inode, mode, alloc_start, + alloc_end - alloc_start, + i_blocksize(inode), + offset + len, &alloc_hint); + unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, + lockend, &cached_state, GFP_KERNEL); + /* btrfs_prealloc_file_range releases reserved space on error */ + if (ret) + space_reserved = false; - ret = btrfs_punch_hole_lock_range(inode, lockstart, lockend, - &cached_state); - if (ret) - goto out; - ret = btrfs_prealloc_file_range(inode, mode, alloc_start, - alloc_end - alloc_start, - i_blocksize(inode), - offset + len, &alloc_hint); - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, - lockend, &cached_state, GFP_KERNEL); - /* btrfs_prealloc_file_range releases reserved space on error */ - if (ret) - space_reserved = false; - } out: if (ret && space_reserved) btrfs_free_reserved_data_space(inode, data_reserved,