aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZheng Liu <wenqing.lz@taobao.com>2014-11-25 11:44:37 -0500
committerTheodore Ts'o <tytso@mit.edu>2014-11-25 11:44:37 -0500
commit2f8e0a7c6c89f850ebd5d6c0b9a08317030d1b89 (patch)
tree4e03e95c516bab8be44e23861626f0c0f29a3958
parentcbd7584e6ead1b79fb0b81573f158b57fa1f0b49 (diff)
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: Zheng Liu <wenqing.lz@taobao.com> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--fs/ext4/ext4.h4
-rw-r--r--fs/ext4/extents.c31
-rw-r--r--fs/ext4/inode.c6
-rw-r--r--include/trace/events/ext4.h3
4 files changed, 20 insertions, 24 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 7b3f3b1decff..98da4cda9d18 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -556,10 +556,8 @@ enum {
556#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080 556#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
557 /* Do not take i_data_sem locking in ext4_map_blocks */ 557 /* Do not take i_data_sem locking in ext4_map_blocks */
558#define EXT4_GET_BLOCKS_NO_LOCK 0x0100 558#define EXT4_GET_BLOCKS_NO_LOCK 0x0100
559 /* Do not put hole in extent cache */
560#define EXT4_GET_BLOCKS_NO_PUT_HOLE 0x0200
561 /* Convert written extents to unwritten */ 559 /* Convert written extents to unwritten */
562#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0400 560#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0200
563 561
564/* 562/*
565 * The bit position of these flags must not overlap with any of the 563 * The bit position of these flags must not overlap with any of the
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 7ef2f11aca56..1ee24d74270f 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2306,16 +2306,16 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
2306 ext4_lblk_t block) 2306 ext4_lblk_t block)
2307{ 2307{
2308 int depth = ext_depth(inode); 2308 int depth = ext_depth(inode);
2309 unsigned long len = 0; 2309 ext4_lblk_t len;
2310 ext4_lblk_t lblock = 0; 2310 ext4_lblk_t lblock;
2311 struct ext4_extent *ex; 2311 struct ext4_extent *ex;
2312 struct extent_status es;
2312 2313
2313 ex = path[depth].p_ext; 2314 ex = path[depth].p_ext;
2314 if (ex == NULL) { 2315 if (ex == NULL) {
2315 /* 2316 /* there is no extent yet, so gap is [0;-] */
2316 * there is no extent yet, so gap is [0;-] and we 2317 lblock = 0;
2317 * don't cache it 2318 len = EXT_MAX_BLOCKS;
2318 */
2319 ext_debug("cache gap(whole file):"); 2319 ext_debug("cache gap(whole file):");
2320 } else if (block < le32_to_cpu(ex->ee_block)) { 2320 } else if (block < le32_to_cpu(ex->ee_block)) {
2321 lblock = block; 2321 lblock = block;
@@ -2324,9 +2324,6 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
2324 block, 2324 block,
2325 le32_to_cpu(ex->ee_block), 2325 le32_to_cpu(ex->ee_block),
2326 ext4_ext_get_actual_len(ex)); 2326 ext4_ext_get_actual_len(ex));
2327 if (!ext4_find_delalloc_range(inode, lblock, lblock + len - 1))
2328 ext4_es_insert_extent(inode, lblock, len, ~0,
2329 EXTENT_STATUS_HOLE);
2330 } else if (block >= le32_to_cpu(ex->ee_block) 2327 } else if (block >= le32_to_cpu(ex->ee_block)
2331 + ext4_ext_get_actual_len(ex)) { 2328 + ext4_ext_get_actual_len(ex)) {
2332 ext4_lblk_t next; 2329 ext4_lblk_t next;
@@ -2340,14 +2337,19 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
2340 block); 2337 block);
2341 BUG_ON(next == lblock); 2338 BUG_ON(next == lblock);
2342 len = next - lblock; 2339 len = next - lblock;
2343 if (!ext4_find_delalloc_range(inode, lblock, lblock + len - 1))
2344 ext4_es_insert_extent(inode, lblock, len, ~0,
2345 EXTENT_STATUS_HOLE);
2346 } else { 2340 } else {
2347 BUG(); 2341 BUG();
2348 } 2342 }
2349 2343
2350 ext_debug(" -> %u:%lu\n", lblock, len); 2344 ext4_es_find_delayed_extent_range(inode, lblock, lblock + len - 1, &es);
2345 if (es.es_len) {
2346 /* There's delayed extent containing lblock? */
2347 if (es.es_lblk <= lblock)
2348 return;
2349 len = min(es.es_lblk - lblock, len);
2350 }
2351 ext_debug(" -> %u:%u\n", lblock, len);
2352 ext4_es_insert_extent(inode, lblock, len, ~0, EXTENT_STATUS_HOLE);
2351} 2353}
2352 2354
2353/* 2355/*
@@ -4368,8 +4370,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
4368 * put just found gap into cache to speed up 4370 * put just found gap into cache to speed up
4369 * subsequent requests 4371 * subsequent requests
4370 */ 4372 */
4371 if ((flags & EXT4_GET_BLOCKS_NO_PUT_HOLE) == 0) 4373 ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
4372 ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
4373 goto out2; 4374 goto out2;
4374 } 4375 }
4375 4376
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 2315e45161ee..d5a46a8df70b 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1432,11 +1432,9 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
1432 if (ext4_has_inline_data(inode)) 1432 if (ext4_has_inline_data(inode))
1433 retval = 0; 1433 retval = 0;
1434 else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) 1434 else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
1435 retval = ext4_ext_map_blocks(NULL, inode, map, 1435 retval = ext4_ext_map_blocks(NULL, inode, map, 0);
1436 EXT4_GET_BLOCKS_NO_PUT_HOLE);
1437 else 1436 else
1438 retval = ext4_ind_map_blocks(NULL, inode, map, 1437 retval = ext4_ind_map_blocks(NULL, inode, map, 0);
1439 EXT4_GET_BLOCKS_NO_PUT_HOLE);
1440 1438
1441add_delayed: 1439add_delayed:
1442 if (retval == 0) { 1440 if (retval == 0) {
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index bb7dcbe99652..cd37a584ee88 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -43,8 +43,7 @@ struct extent_status;
43 { EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \ 43 { EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \
44 { EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \ 44 { EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \
45 { EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }, \ 45 { EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }, \
46 { EXT4_GET_BLOCKS_NO_LOCK, "NO_LOCK" }, \ 46 { EXT4_GET_BLOCKS_NO_LOCK, "NO_LOCK" })
47 { EXT4_GET_BLOCKS_NO_PUT_HOLE, "NO_PUT_HOLE" })
48 47
49#define show_mflags(flags) __print_flags(flags, "", \ 48#define show_mflags(flags) __print_flags(flags, "", \
50 { EXT4_MAP_NEW, "N" }, \ 49 { EXT4_MAP_NEW, "N" }, \