]> Gentwo Git Trees - linux/.git/commitdiff
ext4: make ext4_es_lookup_extent() pass out the extent seq counter
authorZhang Yi <yi.zhang@huawei.com>
Mon, 13 Oct 2025 01:51:19 +0000 (09:51 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 6 Nov 2025 15:44:39 +0000 (10:44 -0500)
When querying extents in the extent status tree, we should hold the
data_sem if we want to obtain the sequence number as a valid cookie
simultaneously. However, currently, ext4_map_blocks() calls
ext4_es_lookup_extent() without holding data_sem. Therefore, we should
acquire i_es_lock instead, which also ensures that the sequence cookie
and the extent remain consistent. Consequently, make
ext4_es_lookup_extent() to pass out the sequence number when necessary.

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Message-ID: <20251013015128.499308-4-yi.zhang@huaweicloud.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/extents.c
fs/ext4/extents_status.c
fs/ext4/extents_status.h
fs/ext4/inode.c

index ca5499e9412b078a136142c04125b3219083b5c5..c7d219e6c6d89f2b0b5121414c09cdbcc8b8c36b 100644 (file)
@@ -2213,7 +2213,7 @@ static int ext4_fill_es_cache_info(struct inode *inode,
        while (block <= end) {
                next = 0;
                flags = 0;
-               if (!ext4_es_lookup_extent(inode, block, &next, &es))
+               if (!ext4_es_lookup_extent(inode, block, &next, &es, NULL))
                        break;
                if (ext4_es_is_unwritten(&es))
                        flags |= FIEMAP_EXTENT_UNWRITTEN;
index c3daa57ecd359d5cf2561febde2b8a7bd1412689..e04fbf10fe4f856b5d46effd4fa3b5c0270dcbd3 100644 (file)
@@ -1039,8 +1039,8 @@ void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk,
  * Return: 1 on found, 0 on not
  */
 int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
-                         ext4_lblk_t *next_lblk,
-                         struct extent_status *es)
+                         ext4_lblk_t *next_lblk, struct extent_status *es,
+                         u64 *pseq)
 {
        struct ext4_es_tree *tree;
        struct ext4_es_stats *stats;
@@ -1099,6 +1099,8 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
                        } else
                                *next_lblk = 0;
                }
+               if (pseq)
+                       *pseq = EXT4_I(inode)->i_es_seq;
        } else {
                percpu_counter_inc(&stats->es_stats_cache_misses);
        }
index 8f9c008d11e810eca2b1cfd5af987b9b5a380d21..f3396cf32b446492f6f6769e0479fe8d3712a039 100644 (file)
@@ -148,7 +148,7 @@ extern void ext4_es_find_extent_range(struct inode *inode,
                                      struct extent_status *es);
 extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
                                 ext4_lblk_t *next_lblk,
-                                struct extent_status *es);
+                                struct extent_status *es, u64 *pseq);
 extern bool ext4_es_scan_range(struct inode *inode,
                               int (*matching_fn)(struct extent_status *es),
                               ext4_lblk_t lblk, ext4_lblk_t end);
index 6356340b768de438a3da5e84f245f6e925f00cd1..b62c1a87ed6bf22483cadd5096015985cd50a362 100644 (file)
@@ -649,7 +649,7 @@ static int ext4_map_create_blocks(handle_t *handle, struct inode *inode,
         * extent status tree.
         */
        if (flags & EXT4_GET_BLOCKS_PRE_IO &&
-           ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
+           ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es, NULL)) {
                if (ext4_es_is_written(&es))
                        return retval;
        }
@@ -723,7 +723,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
                ext4_check_map_extents_env(inode);
 
        /* Lookup extent status tree firstly */
-       if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
+       if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es, NULL)) {
                if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) {
                        map->m_pblk = ext4_es_pblock(&es) +
                                        map->m_lblk - es.es_lblk;
@@ -1908,7 +1908,7 @@ static int ext4_da_map_blocks(struct inode *inode, struct ext4_map_blocks *map)
        ext4_check_map_extents_env(inode);
 
        /* Lookup extent status tree firstly */
-       if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
+       if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es, NULL)) {
                map->m_len = min_t(unsigned int, map->m_len,
                                   es.es_len - (map->m_lblk - es.es_lblk));
 
@@ -1961,7 +1961,7 @@ static int ext4_da_map_blocks(struct inode *inode, struct ext4_map_blocks *map)
         * is held in write mode, before inserting a new da entry in
         * the extent status tree.
         */
-       if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
+       if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es, NULL)) {
                map->m_len = min_t(unsigned int, map->m_len,
                                   es.es_len - (map->m_lblk - es.es_lblk));