Commit 2f8e0a7c authored by Zheng Liu's avatar Zheng Liu Committed by Theodore Ts'o

ext4: cache extent hole in extent status tree for ext4_da_map_blocks()

Currently extent status tree doesn't cache extent hole when a write
looks up in extent tree to make sure whether a block has been allocated
or not.  In this case, we don't put extent hole in extent cache because
later this extent might be removed and a new delayed extent might be
added back.  But it will cause a defect when we do a lot of writes.  If
we don't put extent hole in extent cache, the following writes also need
to access extent tree to look at whether or not a block has been
allocated.  It brings a cache miss.  This commit fixes this defect.
Also if the inode doesn't have any extent, this extent hole will be
cached as well.

Cc: Andreas Dilger <adilger.kernel@dilger.ca>
Signed-off-by: default avatarZheng Liu <wenqing.lz@taobao.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent cbd7584e
...@@ -556,10 +556,8 @@ enum { ...@@ -556,10 +556,8 @@ enum {
#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080 #define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
/* Do not take i_data_sem locking in ext4_map_blocks */ /* Do not take i_data_sem locking in ext4_map_blocks */
#define EXT4_GET_BLOCKS_NO_LOCK 0x0100 #define EXT4_GET_BLOCKS_NO_LOCK 0x0100
/* Do not put hole in extent cache */
#define EXT4_GET_BLOCKS_NO_PUT_HOLE 0x0200
/* Convert written extents to unwritten */ /* Convert written extents to unwritten */
#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0400 #define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0200
/* /*
* The bit position of these flags must not overlap with any of the * The bit position of these flags must not overlap with any of the
......
...@@ -2306,16 +2306,16 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path, ...@@ -2306,16 +2306,16 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
ext4_lblk_t block) ext4_lblk_t block)
{ {
int depth = ext_depth(inode); int depth = ext_depth(inode);
unsigned long len = 0; ext4_lblk_t len;
ext4_lblk_t lblock = 0; ext4_lblk_t lblock;
struct ext4_extent *ex; struct ext4_extent *ex;
struct extent_status es;
ex = path[depth].p_ext; ex = path[depth].p_ext;
if (ex == NULL) { if (ex == NULL) {
/* /* there is no extent yet, so gap is [0;-] */
* there is no extent yet, so gap is [0;-] and we lblock = 0;
* don't cache it len = EXT_MAX_BLOCKS;
*/
ext_debug("cache gap(whole file):"); ext_debug("cache gap(whole file):");
} else if (block < le32_to_cpu(ex->ee_block)) { } else if (block < le32_to_cpu(ex->ee_block)) {
lblock = block; lblock = block;
...@@ -2324,9 +2324,6 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path, ...@@ -2324,9 +2324,6 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
block, block,
le32_to_cpu(ex->ee_block), le32_to_cpu(ex->ee_block),
ext4_ext_get_actual_len(ex)); ext4_ext_get_actual_len(ex));
if (!ext4_find_delalloc_range(inode, lblock, lblock + len - 1))
ext4_es_insert_extent(inode, lblock, len, ~0,
EXTENT_STATUS_HOLE);
} else if (block >= le32_to_cpu(ex->ee_block) } else if (block >= le32_to_cpu(ex->ee_block)
+ ext4_ext_get_actual_len(ex)) { + ext4_ext_get_actual_len(ex)) {
ext4_lblk_t next; ext4_lblk_t next;
...@@ -2340,14 +2337,19 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path, ...@@ -2340,14 +2337,19 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
block); block);
BUG_ON(next == lblock); BUG_ON(next == lblock);
len = next - lblock; len = next - lblock;
if (!ext4_find_delalloc_range(inode, lblock, lblock + len - 1))
ext4_es_insert_extent(inode, lblock, len, ~0,
EXTENT_STATUS_HOLE);
} else { } else {
BUG(); BUG();
} }
ext_debug(" -> %u:%lu\n", lblock, len); ext4_es_find_delayed_extent_range(inode, lblock, lblock + len - 1, &es);
if (es.es_len) {
/* There's delayed extent containing lblock? */
if (es.es_lblk <= lblock)
return;
len = min(es.es_lblk - lblock, len);
}
ext_debug(" -> %u:%u\n", lblock, len);
ext4_es_insert_extent(inode, lblock, len, ~0, EXTENT_STATUS_HOLE);
} }
/* /*
...@@ -4368,8 +4370,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ...@@ -4368,8 +4370,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
* put just found gap into cache to speed up * put just found gap into cache to speed up
* subsequent requests * subsequent requests
*/ */
if ((flags & EXT4_GET_BLOCKS_NO_PUT_HOLE) == 0) ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
goto out2; goto out2;
} }
......
...@@ -1432,11 +1432,9 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, ...@@ -1432,11 +1432,9 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
if (ext4_has_inline_data(inode)) if (ext4_has_inline_data(inode))
retval = 0; retval = 0;
else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
retval = ext4_ext_map_blocks(NULL, inode, map, retval = ext4_ext_map_blocks(NULL, inode, map, 0);
EXT4_GET_BLOCKS_NO_PUT_HOLE);
else else
retval = ext4_ind_map_blocks(NULL, inode, map, retval = ext4_ind_map_blocks(NULL, inode, map, 0);
EXT4_GET_BLOCKS_NO_PUT_HOLE);
add_delayed: add_delayed:
if (retval == 0) { if (retval == 0) {
......
...@@ -43,8 +43,7 @@ struct extent_status; ...@@ -43,8 +43,7 @@ struct extent_status;
{ EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \ { EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \
{ EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \ { EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \
{ EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }, \ { EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }, \
{ EXT4_GET_BLOCKS_NO_LOCK, "NO_LOCK" }, \ { EXT4_GET_BLOCKS_NO_LOCK, "NO_LOCK" })
{ EXT4_GET_BLOCKS_NO_PUT_HOLE, "NO_PUT_HOLE" })
#define show_mflags(flags) __print_flags(flags, "", \ #define show_mflags(flags) __print_flags(flags, "", \
{ EXT4_MAP_NEW, "N" }, \ { EXT4_MAP_NEW, "N" }, \
......
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