Skip to content

Commit

Permalink
ext4: Clear the EXT4_EOFBLOCKS_FL flag only when warranted
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Theodore Ts'o committed May 17, 2010
1 parent f70f362 commit 786ec79
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -3319,7 +3319,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
struct ext4_extent_header *eh;
struct ext4_extent newex, *ex, *last_ex;
ext4_fsblk_t newblock;
int err = 0, depth, ret, cache_type;
int i, err = 0, depth, ret, cache_type;
unsigned int allocated = 0;
struct ext4_allocation_request ar;
ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
Expand Down Expand Up @@ -3508,8 +3508,20 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
goto out2;
}
last_ex = EXT_LAST_EXTENT(eh);
if (map->m_lblk + ar.len > le32_to_cpu(last_ex->ee_block)
+ ext4_ext_get_actual_len(last_ex))
/*
* If the current leaf block was reached by looking at
* the last index block all the way down the tree, and
* we are extending the inode beyond the last extent
* in the current leaf block, then clear the
* EOFBLOCKS_FL flag.
*/
for (i = depth-1; i >= 0; i--) {
if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr))
break;
}
if ((i < 0) &&
(map->m_lblk + ar.len > le32_to_cpu(last_ex->ee_block) +
ext4_ext_get_actual_len(last_ex)))
ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
}
err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
Expand Down

0 comments on commit 786ec79

Please sign in to comment.