Commit a4e5d88b authored by Dmitry Monakhov's avatar Dmitry Monakhov Committed by Theodore Ts'o

ext4: update EOFBLOCKS flag on fallocate properly

EOFBLOCK_FL should be updated if called w/o FALLOCATE_FL_KEEP_SIZE
Currently it happens only if new extent was allocated.

TESTCASE:
fallocate test_file -n -l4096
fallocate test_file -l4096
Last fallocate cmd has updated size, but keept EOFBLOCK_FL set. And
fsck will complain about that.

Also remove ping pong in ext4_fallocate() in case of new extents,
where ext4_ext_map_blocks() clear EOFBLOCKS bit, and later
ext4_falloc_update_inode() restore it again.
Signed-off-by: default avatarDmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 750c9c47
...@@ -539,6 +539,8 @@ struct ext4_new_group_data { ...@@ -539,6 +539,8 @@ struct ext4_new_group_data {
#define EXT4_GET_BLOCKS_PUNCH_OUT_EXT 0x0020 #define EXT4_GET_BLOCKS_PUNCH_OUT_EXT 0x0020
/* Don't normalize allocation size (used for fallocate) */ /* Don't normalize allocation size (used for fallocate) */
#define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040 #define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040
/* Request will not result in inode size update (user for fallocate) */
#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
/* /*
* Flags used by ext4_free_blocks * Flags used by ext4_free_blocks
......
...@@ -3432,14 +3432,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, ...@@ -3432,14 +3432,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
/* buffered write, writepage time, convert*/ /* buffered write, writepage time, convert*/
ret = ext4_ext_convert_to_initialized(handle, inode, map, path); ret = ext4_ext_convert_to_initialized(handle, inode, map, path);
if (ret >= 0) { if (ret >= 0)
ext4_update_inode_fsync_trans(handle, inode, 1); ext4_update_inode_fsync_trans(handle, inode, 1);
err = check_eofblocks_fl(handle, inode, map->m_lblk, path,
map->m_len);
if (err < 0)
goto out2;
}
out: out:
if (ret <= 0) { if (ret <= 0) {
err = ret; err = ret;
...@@ -3480,6 +3474,12 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, ...@@ -3480,6 +3474,12 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
map_out: map_out:
map->m_flags |= EXT4_MAP_MAPPED; map->m_flags |= EXT4_MAP_MAPPED;
if ((flags & EXT4_GET_BLOCKS_KEEP_SIZE) == 0) {
err = check_eofblocks_fl(handle, inode, map->m_lblk, path,
map->m_len);
if (err < 0)
goto out2;
}
out1: out1:
if (allocated > map->m_len) if (allocated > map->m_len)
allocated = map->m_len; allocated = map->m_len;
...@@ -3955,7 +3955,10 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ...@@ -3955,7 +3955,10 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
map->m_flags |= EXT4_MAP_UNINIT; map->m_flags |= EXT4_MAP_UNINIT;
} }
err = check_eofblocks_fl(handle, inode, map->m_lblk, path, ar.len); err = 0;
if ((flags & EXT4_GET_BLOCKS_KEEP_SIZE) == 0)
err = check_eofblocks_fl(handle, inode, map->m_lblk,
path, ar.len);
if (!err) if (!err)
err = ext4_ext_insert_extent(handle, inode, path, err = ext4_ext_insert_extent(handle, inode, path,
&newex, flags); &newex, flags);
...@@ -4214,6 +4217,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ...@@ -4214,6 +4217,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
int ret = 0; int ret = 0;
int ret2 = 0; int ret2 = 0;
int retries = 0; int retries = 0;
int flags;
struct ext4_map_blocks map; struct ext4_map_blocks map;
unsigned int credits, blkbits = inode->i_blkbits; unsigned int credits, blkbits = inode->i_blkbits;
...@@ -4250,6 +4254,10 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ...@@ -4250,6 +4254,10 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); trace_ext4_fallocate_exit(inode, offset, max_blocks, ret);
return ret; return ret;
} }
flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT |
EXT4_GET_BLOCKS_NO_NORMALIZE;
if (mode & FALLOC_FL_KEEP_SIZE)
flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
retry: retry:
while (ret >= 0 && ret < max_blocks) { while (ret >= 0 && ret < max_blocks) {
map.m_lblk = map.m_lblk + ret; map.m_lblk = map.m_lblk + ret;
...@@ -4259,9 +4267,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ...@@ -4259,9 +4267,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
ret = PTR_ERR(handle); ret = PTR_ERR(handle);
break; break;
} }
ret = ext4_map_blocks(handle, inode, &map, ret = ext4_map_blocks(handle, inode, &map, flags);
EXT4_GET_BLOCKS_CREATE_UNINIT_EXT |
EXT4_GET_BLOCKS_NO_NORMALIZE);
if (ret <= 0) { if (ret <= 0) {
#ifdef EXT4FS_DEBUG #ifdef EXT4FS_DEBUG
WARN_ON(ret <= 0); WARN_ON(ret <= 0);
......
...@@ -477,9 +477,11 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, ...@@ -477,9 +477,11 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
*/ */
down_read((&EXT4_I(inode)->i_data_sem)); down_read((&EXT4_I(inode)->i_data_sem));
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
retval = ext4_ext_map_blocks(handle, inode, map, 0); retval = ext4_ext_map_blocks(handle, inode, map, flags &
EXT4_GET_BLOCKS_KEEP_SIZE);
} else { } else {
retval = ext4_ind_map_blocks(handle, inode, map, 0); retval = ext4_ind_map_blocks(handle, inode, map, flags &
EXT4_GET_BLOCKS_KEEP_SIZE);
} }
up_read((&EXT4_I(inode)->i_data_sem)); up_read((&EXT4_I(inode)->i_data_sem));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment