ext4: lookup block mapping in extent status tree
After tracking all extent status, we already have a extent cache in memory. Every time we want to lookup a block mapping, we can first try to lookup it in extent status tree to avoid a potential disk I/O. A new function called ext4_es_lookup_extent is defined to finish this work. When we try to lookup a block mapping, we always call ext4_map_blocks and/or ext4_da_map_blocks. So in these functions we first try to lookup a block mapping in extent status tree. A new flag EXT4_GET_BLOCKS_NO_PUT_HOLE is used in ext4_da_map_blocks in order not to put a hole into extent status tree because this hole will be converted to delayed extent in the tree immediately. Signed-off-by: Zheng Liu <wenqing.lz@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: Jan kara <jack@suse.cz>
This commit is contained in:
parent
f7fec032aa
commit
d100eef244
6 changed files with 192 additions and 3 deletions
|
@ -507,12 +507,33 @@ static pgoff_t ext4_num_dirty_pages(struct inode *inode, pgoff_t idx,
|
|||
int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
||||
struct ext4_map_blocks *map, int flags)
|
||||
{
|
||||
struct extent_status es;
|
||||
int retval;
|
||||
|
||||
map->m_flags = 0;
|
||||
ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u,"
|
||||
"logical block %lu\n", inode->i_ino, flags, map->m_len,
|
||||
(unsigned long) map->m_lblk);
|
||||
|
||||
/* Lookup extent status tree firstly */
|
||||
if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) {
|
||||
if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) {
|
||||
map->m_pblk = ext4_es_pblock(&es) +
|
||||
map->m_lblk - es.es_lblk;
|
||||
map->m_flags |= ext4_es_is_written(&es) ?
|
||||
EXT4_MAP_MAPPED : EXT4_MAP_UNWRITTEN;
|
||||
retval = es.es_len - (map->m_lblk - es.es_lblk);
|
||||
if (retval > map->m_len)
|
||||
retval = map->m_len;
|
||||
map->m_len = retval;
|
||||
} else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) {
|
||||
retval = 0;
|
||||
} else {
|
||||
BUG_ON(1);
|
||||
}
|
||||
goto found;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to see if we can get the block without requesting a new
|
||||
* file system block.
|
||||
|
@ -544,6 +565,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
|||
if (!(flags & EXT4_GET_BLOCKS_NO_LOCK))
|
||||
up_read((&EXT4_I(inode)->i_data_sem));
|
||||
|
||||
found:
|
||||
if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
|
||||
int ret = check_block_validity(inode, map);
|
||||
if (ret != 0)
|
||||
|
@ -1743,6 +1765,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
|
|||
struct ext4_map_blocks *map,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
struct extent_status es;
|
||||
int retval;
|
||||
sector_t invalid_block = ~((sector_t) 0xffff);
|
||||
|
||||
|
@ -1753,6 +1776,42 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
|
|||
ext_debug("ext4_da_map_blocks(): inode %lu, max_blocks %u,"
|
||||
"logical block %lu\n", inode->i_ino, map->m_len,
|
||||
(unsigned long) map->m_lblk);
|
||||
|
||||
/* Lookup extent status tree firstly */
|
||||
if (ext4_es_lookup_extent(inode, iblock, &es)) {
|
||||
|
||||
if (ext4_es_is_hole(&es)) {
|
||||
retval = 0;
|
||||
down_read((&EXT4_I(inode)->i_data_sem));
|
||||
goto add_delayed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delayed extent could be allocated by fallocate.
|
||||
* So we need to check it.
|
||||
*/
|
||||
if (ext4_es_is_delayed(&es) && !ext4_es_is_unwritten(&es)) {
|
||||
map_bh(bh, inode->i_sb, invalid_block);
|
||||
set_buffer_new(bh);
|
||||
set_buffer_delay(bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
map->m_pblk = ext4_es_pblock(&es) + iblock - es.es_lblk;
|
||||
retval = es.es_len - (iblock - es.es_lblk);
|
||||
if (retval > map->m_len)
|
||||
retval = map->m_len;
|
||||
map->m_len = retval;
|
||||
if (ext4_es_is_written(&es))
|
||||
map->m_flags |= EXT4_MAP_MAPPED;
|
||||
else if (ext4_es_is_unwritten(&es))
|
||||
map->m_flags |= EXT4_MAP_UNWRITTEN;
|
||||
else
|
||||
BUG_ON(1);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to see if we can get the block without requesting a new
|
||||
* file system block.
|
||||
|
@ -1771,10 +1830,13 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
|
|||
map->m_flags |= EXT4_MAP_FROM_CLUSTER;
|
||||
retval = 0;
|
||||
} else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
|
||||
retval = ext4_ext_map_blocks(NULL, inode, map, 0);
|
||||
retval = ext4_ext_map_blocks(NULL, inode, map,
|
||||
EXT4_GET_BLOCKS_NO_PUT_HOLE);
|
||||
else
|
||||
retval = ext4_ind_map_blocks(NULL, inode, map, 0);
|
||||
retval = ext4_ind_map_blocks(NULL, inode, map,
|
||||
EXT4_GET_BLOCKS_NO_PUT_HOLE);
|
||||
|
||||
add_delayed:
|
||||
if (retval == 0) {
|
||||
int ret;
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue