ext4: factor out determining of hole size
ext4_ext_put_gap_in_cache() determines hole size in the extent tree, then trims this with possible delayed allocated blocks, and inserts the result into the extent status tree. Factor out determination of the size of the hole in the extent tree as we will need this information in ext4_ext_map_blocks() as well. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
87d8a74b56
commit
140a52508a
1 changed files with 56 additions and 42 deletions
|
@ -2298,60 +2298,70 @@ static int ext4_fill_fiemap_extents(struct inode *inode,
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_ext_determine_hole - determine hole around given block
|
||||
* @inode: inode we lookup in
|
||||
* @path: path in extent tree to @lblk
|
||||
* @lblk: pointer to logical block around which we want to determine hole
|
||||
*
|
||||
* Determine hole length (and start if easily possible) around given logical
|
||||
* block. We don't try too hard to find the beginning of the hole but @path
|
||||
* actually points to extent before @lblk, we provide it.
|
||||
*
|
||||
* The function returns the length of a hole starting at @lblk. We update @lblk
|
||||
* to the beginning of the hole if we managed to find it.
|
||||
*/
|
||||
static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
|
||||
struct ext4_ext_path *path,
|
||||
ext4_lblk_t *lblk)
|
||||
{
|
||||
int depth = ext_depth(inode);
|
||||
struct ext4_extent *ex;
|
||||
ext4_lblk_t len;
|
||||
|
||||
ex = path[depth].p_ext;
|
||||
if (ex == NULL) {
|
||||
/* there is no extent yet, so gap is [0;-] */
|
||||
*lblk = 0;
|
||||
len = EXT_MAX_BLOCKS;
|
||||
} else if (*lblk < le32_to_cpu(ex->ee_block)) {
|
||||
len = le32_to_cpu(ex->ee_block) - *lblk;
|
||||
} else if (*lblk >= le32_to_cpu(ex->ee_block)
|
||||
+ ext4_ext_get_actual_len(ex)) {
|
||||
ext4_lblk_t next;
|
||||
|
||||
*lblk = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex);
|
||||
next = ext4_ext_next_allocated_block(path);
|
||||
BUG_ON(next == *lblk);
|
||||
len = next - *lblk;
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_ext_put_gap_in_cache:
|
||||
* calculate boundaries of the gap that the requested block fits into
|
||||
* and cache this gap
|
||||
*/
|
||||
static void
|
||||
ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
|
||||
ext4_lblk_t block)
|
||||
ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start,
|
||||
ext4_lblk_t hole_len)
|
||||
{
|
||||
int depth = ext_depth(inode);
|
||||
ext4_lblk_t len;
|
||||
ext4_lblk_t lblock;
|
||||
struct ext4_extent *ex;
|
||||
struct extent_status es;
|
||||
|
||||
ex = path[depth].p_ext;
|
||||
if (ex == NULL) {
|
||||
/* there is no extent yet, so gap is [0;-] */
|
||||
lblock = 0;
|
||||
len = EXT_MAX_BLOCKS;
|
||||
ext_debug("cache gap(whole file):");
|
||||
} else if (block < le32_to_cpu(ex->ee_block)) {
|
||||
lblock = block;
|
||||
len = le32_to_cpu(ex->ee_block) - block;
|
||||
ext_debug("cache gap(before): %u [%u:%u]",
|
||||
block,
|
||||
le32_to_cpu(ex->ee_block),
|
||||
ext4_ext_get_actual_len(ex));
|
||||
} else if (block >= le32_to_cpu(ex->ee_block)
|
||||
+ ext4_ext_get_actual_len(ex)) {
|
||||
ext4_lblk_t next;
|
||||
lblock = le32_to_cpu(ex->ee_block)
|
||||
+ ext4_ext_get_actual_len(ex);
|
||||
|
||||
next = ext4_ext_next_allocated_block(path);
|
||||
ext_debug("cache gap(after): [%u:%u] %u",
|
||||
le32_to_cpu(ex->ee_block),
|
||||
ext4_ext_get_actual_len(ex),
|
||||
block);
|
||||
BUG_ON(next == lblock);
|
||||
len = next - lblock;
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
|
||||
ext4_es_find_delayed_extent_range(inode, lblock, lblock + len - 1, &es);
|
||||
ext4_es_find_delayed_extent_range(inode, hole_start,
|
||||
hole_start + hole_len - 1, &es);
|
||||
if (es.es_len) {
|
||||
/* There's delayed extent containing lblock? */
|
||||
if (es.es_lblk <= lblock)
|
||||
if (es.es_lblk <= hole_start)
|
||||
return;
|
||||
len = min(es.es_lblk - lblock, len);
|
||||
hole_len = min(es.es_lblk - hole_start, hole_len);
|
||||
}
|
||||
ext_debug(" -> %u:%u\n", lblock, len);
|
||||
ext4_es_insert_extent(inode, lblock, len, ~0, EXTENT_STATUS_HOLE);
|
||||
ext_debug(" -> %u:%u\n", hole_start, hole_len);
|
||||
ext4_es_insert_extent(inode, hole_start, hole_len, ~0,
|
||||
EXTENT_STATUS_HOLE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4362,11 +4372,15 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
|
|||
* we couldn't try to create block if create flag is zero
|
||||
*/
|
||||
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
|
||||
ext4_lblk_t hole_start, hole_len;
|
||||
|
||||
/*
|
||||
* put just found gap into cache to speed up
|
||||
* subsequent requests
|
||||
*/
|
||||
ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
|
||||
hole_start = map->m_lblk;
|
||||
hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
|
||||
ext4_ext_put_gap_in_cache(inode, hole_start, hole_len);
|
||||
goto out2;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue