aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2010-05-17 00:00:00 -0400
committerTheodore Ts'o <tytso@mit.edu>2010-05-17 00:00:00 -0400
commit786ec7915e530936b9eb2e3d12274145cab7aa7d (patch)
treebbdfd4189ef769196808698e68862d4a192595e6 /fs/ext4
parentf70f362b4a6fe47c239dbfb3efc0cc2c10e4f09c (diff)
ext4: Clear the EXT4_EOFBLOCKS_FL flag only when warranted
Dimitry Monakhov discovered an edge case where it was possible for the EXT4_EOFBLOCKS_FL flag could get cleared unnecessarily. This is true; I have a test case that can be exercised via downloading and decompressing the file: wget ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/ext4-testcases/eofblocks-fl-test-case.img.bz2 bunzip2 eofblocks-fl-test-case.img dd if=/dev/zero of=eofblocks-fl-test-case.img bs=1k seek=17925 bs=1k count=1 conv=notrunc However, triggering it in real life is highly unlikely since it requires an extremely fragmented sparse file with a hole in exactly the right place in the extent tree. (It actually took quite a bit of work to generate this test case.) Still, it's nice to get even extreme corner cases to be correct, so this patch makes sure that we don't clear the EXT4_EOFBLOCKS_FL incorrectly even in this corner case. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/extents.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index e40d2b793f2d..ffcaa1137def 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3319,7 +3319,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
3319 struct ext4_extent_header *eh; 3319 struct ext4_extent_header *eh;
3320 struct ext4_extent newex, *ex, *last_ex; 3320 struct ext4_extent newex, *ex, *last_ex;
3321 ext4_fsblk_t newblock; 3321 ext4_fsblk_t newblock;
3322 int err = 0, depth, ret, cache_type; 3322 int i, err = 0, depth, ret, cache_type;
3323 unsigned int allocated = 0; 3323 unsigned int allocated = 0;
3324 struct ext4_allocation_request ar; 3324 struct ext4_allocation_request ar;
3325 ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio; 3325 ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
@@ -3508,8 +3508,20 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
3508 goto out2; 3508 goto out2;
3509 } 3509 }
3510 last_ex = EXT_LAST_EXTENT(eh); 3510 last_ex = EXT_LAST_EXTENT(eh);
3511 if (map->m_lblk + ar.len > le32_to_cpu(last_ex->ee_block) 3511 /*
3512 + ext4_ext_get_actual_len(last_ex)) 3512 * If the current leaf block was reached by looking at
3513 * the last index block all the way down the tree, and
3514 * we are extending the inode beyond the last extent
3515 * in the current leaf block, then clear the
3516 * EOFBLOCKS_FL flag.
3517 */
3518 for (i = depth-1; i >= 0; i--) {
3519 if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr))
3520 break;
3521 }
3522 if ((i < 0) &&
3523 (map->m_lblk + ar.len > le32_to_cpu(last_ex->ee_block) +
3524 ext4_ext_get_actual_len(last_ex)))
3513 ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS); 3525 ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
3514 } 3526 }
3515 err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); 3527 err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);