ext4: fix for fiemap last-block test
PATCH 1/1 ext4: fix for fiemap last-block test
Carl Henrik Lunde reported and debugged this; the test for the last allocated block was comparing bytes to blocks in this test:
if (logical + length - 1 == EXT_MAX_BLOCK || ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK) flags |= FIEMAP_EXTENT_LAST;
so any extent which ended right at 4G was stopping the extent walk. Just replacing these values with the extent block & length should fix it.
Also give blksize_bits a saner type, and reverse the order of the tests to make the more likely case tested first.
---
fs/ext4/extents.c +3 -3
@@ -3087,7 +3087,7 @@ static int ext4_ext_fiemap_cb(struct ino void *data) {struct fiemap_extent_info *fieinfo = data; -unsigned long blksize_bits = inode->i_sb->s_blocksize_bits; +unsigned char blksize_bits = inode->i_sb->s_blocksize_bits;__u64 logical;__u64 physical;__u64 length;
@@ -3134,8 +3134,8 @@ static int ext4_ext_fiemap_cb(struct ino* * XXX this might miss a single-block extent at EXT_MAX_BLOCK */ -if (logical + length -1 ==EXT_MAX_BLOCK || -ext4_ext_next_allocated_block (path) ==EXT_MAX_BLOCK ) +if (ext4_ext_next_allocated_block (path) ==EXT_MAX_BLOCK || + newex->ec_block + newex->ec_len -1 ==EXT_MAX_BLOCK ) flags |=FIEMAP_EXTENT_LAST ; error = fiemap_fill_next_extent(fieinfo, logical, physical,
Theodore Tso
maintainerThanks, I've pulled this into the ext4 patch queue. While I was testing this, I found an additional bug in ext4's fiemap handling. I'll post that fix as a reply to this message.
- Ted
Theodore Ts'o
maintainerPATCH 1/1 ext4: fix the length returned by fiemap for an unallocated extent
If the file's blocks have not yet been allocated because of delayed allocation, the length of the extent returned by fiemap is incorrect. This commit fixes this bug.
--- fs/ext4/extents.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
fs/ext4/extents.c +8 -1
@@ -3234,8 +3234,15 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,* XXX this might miss a single-block extent at EXT_MAX_BLOCK */ if (ext4_ext_next_allocated_block (path) ==EXT_MAX_BLOCK || - newex->ec_block + newex->ec_len -1 ==EXT_MAX_BLOCK ) + newex->ec_block + newex->ec_len -1 ==EXT_MAX_BLOCK ) { +loff_t size =i_size_read (inode); +loff_t bs =EXT4_BLOCK_SIZE (inode->i_sb); + flags |=FIEMAP_EXTENT_LAST ; +if ((flags &FIEMAP_EXTENT_DELALLOC ) && + logical+length > size) + length = (size - logical + bs -1 ) & ~(bs-1 ); + } error =fiemap_fill_next_extent (fieinfo, logical, physical, length, flags);
Signature · 1 line
1.6.0.4