[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20231213182114.tzwsqpeonr5ok3j2@quack3>
Date: Wed, 13 Dec 2023 19:21:14 +0100
From: Jan Kara <jack@...e.cz>
To: Zhang Yi <yi.zhang@...weicloud.com>
Cc: linux-ext4@...r.kernel.org, tytso@....edu, adilger.kernel@...ger.ca,
jack@...e.cz, ritesh.list@...il.com, yi.zhang@...wei.com,
chengzhihao1@...wei.com, yukuai3@...wei.com
Subject: Re: [RFC PATCH 3/6] ext4: correct the hole length returned by
ext4_map_blocks()
On Tue 21-11-23 17:34:26, Zhang Yi wrote:
> From: Zhang Yi <yi.zhang@...wei.com>
>
> In ext4_map_blocks(), if we can't find a range of mapping in the
> extents cache, we are calling ext4_ext_map_blocks() to search the real
> path. But if the querying range was tail overlaped by a delayed extent,
> we can't find it on the real extent path, so the returned hole length
> could be larger than it really is.
>
> | querying map |
> v v
> |----------{-------------}{------|----------------}-----...
> ^ ^ ^^ ^
> | uncached | hole extent || delayed extent |
>
> We have to adjust the mapping length to the next not hole extent's
> lblk before searching the extent path.
>
> Signed-off-by: Zhang Yi <yi.zhang@...wei.com>
So I agree the ext4_ext_determine_hole() does return a hole that does not
reflect possible delalloc extent (it doesn't even need to be straddling the
end of looked up range, does it?). But ext4_ext_put_gap_in_cache() does
actually properly trim the hole length in the status tree so I think the
problem rather is that the trimming should happen in
ext4_ext_determine_hole() instead of ext4_ext_put_gap_in_cache() and that
will also make ext4_map_blocks() return proper hole length? And then
there's no need for this special handling? Or am I missing something?
Honza
> ---
> fs/ext4/inode.c | 24 ++++++++++++++++++++++--
> 1 file changed, 22 insertions(+), 2 deletions(-)
>
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 4ce35f1c8b0a..94e7b8500878 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -479,6 +479,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
> struct ext4_map_blocks *map, int flags)
> {
> struct extent_status es;
> + ext4_lblk_t next;
> int retval;
> int ret = 0;
> #ifdef ES_AGGRESSIVE_TEST
> @@ -502,8 +503,10 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
> return -EFSCORRUPTED;
>
> /* Lookup extent status tree firstly */
> - if (!(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY) &&
> - ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
> + if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY)
> + goto uncached;
> +
> + if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &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;
> @@ -532,6 +535,23 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
> #endif
> goto found;
> }
> + /*
> + * Not found, maybe a hole, need to adjust the map length before
> + * seraching the real extent path. It can prevent incorrect hole
> + * length returned if the following entries have delayed only
> + * ones.
> + */
> + if (!(flags & EXT4_GET_BLOCKS_CREATE) && es.es_lblk > map->m_lblk) {
> + next = es.es_lblk;
> + if (ext4_es_is_hole(&es))
> + next = ext4_es_skip_hole_extent(inode, map->m_lblk,
> + map->m_len);
> + retval = next - map->m_lblk;
> + if (map->m_len > retval)
> + map->m_len = retval;
> + }
> +
> +uncached:
> /*
> * In the query cache no-wait mode, nothing we can do more if we
> * cannot find extent in the cache.
> --
> 2.39.2
>
--
Jan Kara <jack@...e.com>
SUSE Labs, CR
Powered by blists - more mailing lists