diff options
-rw-r--r-- | fs/btrfs/file.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index baad81c1f9a3..06a631f89b1e 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2852,12 +2852,18 @@ static int btrfs_fallocate_update_isize(struct inode *inode, return ret ? ret : ret2; } +enum { + RANGE_BOUNDARY_WRITTEN_EXTENT = 0, + RANGE_BOUNDARY_PREALLOC_EXTENT = 1, + RANGE_BOUNDARY_HOLE = 2, +}; + static int btrfs_zero_range_check_range_boundary(struct inode *inode, u64 offset) { const u64 sectorsize = btrfs_inode_sectorsize(inode); struct extent_map *em; - int ret = 0; + int ret; offset = round_down(offset, sectorsize); em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize, 0); @@ -2865,7 +2871,11 @@ static int btrfs_zero_range_check_range_boundary(struct inode *inode, return PTR_ERR(em); if (em->block_start == EXTENT_MAP_HOLE) - ret = 1; + ret = RANGE_BOUNDARY_HOLE; + else if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) + ret = RANGE_BOUNDARY_PREALLOC_EXTENT; + else + ret = RANGE_BOUNDARY_WRITTEN_EXTENT; free_extent_map(em); return ret; @@ -2974,13 +2984,15 @@ static int btrfs_zero_range(struct inode *inode, ret = btrfs_zero_range_check_range_boundary(inode, offset); if (ret < 0) goto out; - if (ret) { + if (ret == RANGE_BOUNDARY_HOLE) { alloc_start = round_down(offset, sectorsize); ret = 0; - } else { + } else if (ret == RANGE_BOUNDARY_WRITTEN_EXTENT) { ret = btrfs_truncate_block(inode, offset, 0, 0); if (ret) goto out; + } else { + ret = 0; } } @@ -2989,13 +3001,15 @@ static int btrfs_zero_range(struct inode *inode, offset + len); if (ret < 0) goto out; - if (ret) { + if (ret == RANGE_BOUNDARY_HOLE) { alloc_end = round_up(offset + len, sectorsize); ret = 0; - } else { + } else if (ret == RANGE_BOUNDARY_WRITTEN_EXTENT) { ret = btrfs_truncate_block(inode, offset + len, 0, 1); if (ret) goto out; + } else { + ret = 0; } } |