ext4: check env when mapping and modifying extents
authorZhang Yi <yi.zhang@huawei.com>
Wed, 23 Apr 2025 08:52:56 +0000 (16:52 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 15 May 2025 17:14:51 +0000 (13:14 -0400)
Add ext4_check_map_extents_env() to the places where loading extents,
mapping blocks, removing blocks, and modifying extents, excluding the
I/O writeback context. This function will verify whether the locking
mechanisms in place are adequate.

Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Link: https://patch.msgid.link/20250423085257.122685-9-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/extents.c
fs/ext4/inode.c

index b5eb89ef7ae2616b87f58136f9b263e0f11c2650..52bfc042bf4e499d545df969e6f682c3ede22c35 100644 (file)
@@ -611,6 +611,8 @@ int ext4_ext_precache(struct inode *inode)
        if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                return 0;       /* not an extent-mapped inode */
 
+       ext4_check_map_extents_env(inode);
+
        down_read(&ei->i_data_sem);
        depth = ext_depth(inode);
 
@@ -5342,6 +5344,8 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
        start_lblk = offset >> inode->i_blkbits;
        end_lblk = (offset + len) >> inode->i_blkbits;
 
+       ext4_check_map_extents_env(inode);
+
        down_write(&EXT4_I(inode)->i_data_sem);
        ext4_discard_preallocations(inode);
        ext4_es_remove_extent(inode, start_lblk, EXT_MAX_BLOCKS - start_lblk);
@@ -5443,6 +5447,8 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
        start_lblk = offset >> inode->i_blkbits;
        len_lblk = len >> inode->i_blkbits;
 
+       ext4_check_map_extents_env(inode);
+
        down_write(&EXT4_I(inode)->i_data_sem);
        ext4_discard_preallocations(inode);
 
index 5b591a47ff84599abe6b005177a8fcefff279d16..9b0bfbbdb50b9cb2f96f02fa7e6ac5e0db4c6a50 100644 (file)
@@ -650,11 +650,14 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
                return -EFSCORRUPTED;
 
        /*
-        * Do not allow caching of unrelated ranges of extents during I/O
-        * submission.
+        * Callers from the context of data submission are the only exceptions
+        * for regular files that do not hold the i_rwsem or invalidate_lock.
+        * However, caching unrelated ranges is not permitted.
         */
        if (flags & EXT4_GET_BLOCKS_IO_SUBMIT)
                WARN_ON_ONCE(!(flags & EXT4_EX_NOCACHE));
+       else
+               ext4_check_map_extents_env(inode);
 
        /* Lookup extent status tree firstly */
        if (!(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY) &&
@@ -1801,6 +1804,8 @@ static int ext4_da_map_blocks(struct inode *inode, struct ext4_map_blocks *map)
        ext_debug(inode, "max_blocks %u, logical block %lu\n", map->m_len,
                  (unsigned long) map->m_lblk);
 
+       ext4_check_map_extents_env(inode);
+
        /* Lookup extent status tree firstly */
        if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {
                map->m_len = min_t(unsigned int, map->m_len,
@@ -4113,6 +4118,7 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
                ext4_lblk_t hole_len = end_lblk - start_lblk;
 
                ext4_fc_track_inode(handle, inode);
+               ext4_check_map_extents_env(inode);
                down_write(&EXT4_I(inode)->i_data_sem);
                ext4_discard_preallocations(inode);
 
@@ -4266,8 +4272,9 @@ int ext4_truncate(struct inode *inode)
                goto out_stop;
 
        ext4_fc_track_inode(handle, inode);
-       down_write(&EXT4_I(inode)->i_data_sem);
+       ext4_check_map_extents_env(inode);
 
+       down_write(&EXT4_I(inode)->i_data_sem);
        ext4_discard_preallocations(inode);
 
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))