]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ext4: introduce ext4_check_map_extents_env() debug helper
authorZhang Yi <yi.zhang@huawei.com>
Wed, 23 Apr 2025 08:52:55 +0000 (16:52 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 14 May 2025 14:42:13 +0000 (10:42 -0400)
Loading and modifying the extents tree and extent status tree without
holding the inode's i_rwsem or the mapping's invalidate_lock is not
permitted, except during the I/O writeback. Add a new debug helper
ext4_check_map_extents_env(), it will verify whether the extent
loading/modifying context is safe.

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Link: https://patch.msgid.link/20250423085257.122685-8-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/ext4.h
fs/ext4/inode.c

index 218a1e61547ad35fcd46a73cd53164f2174d15c7..3f352f2a6d851a19f4ae06540dbcf0cde5d8db0f 100644 (file)
@@ -2978,6 +2978,7 @@ static inline bool ext4_mb_cr_expensive(enum criteria cr)
 void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw,
                         struct ext4_inode_info *ei);
 int ext4_inode_is_fast_symlink(struct inode *inode);
+void ext4_check_map_extents_env(struct inode *inode);
 struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int);
 struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int);
 int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count,
index 64cadc46e4201b839e9abbe204efd01aec8d629b..5b591a47ff84599abe6b005177a8fcefff279d16 100644 (file)
@@ -416,6 +416,32 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk,
        return ret;
 }
 
+/*
+ * For generic regular files, when updating the extent tree, Ext4 should
+ * hold the i_rwsem and invalidate_lock exclusively. This ensures
+ * exclusion against concurrent page faults, as well as reads and writes.
+ */
+#ifdef CONFIG_EXT4_DEBUG
+void ext4_check_map_extents_env(struct inode *inode)
+{
+       if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY)
+               return;
+
+       if (!S_ISREG(inode->i_mode) ||
+           IS_NOQUOTA(inode) || IS_VERITY(inode) ||
+           is_special_ino(inode->i_sb, inode->i_ino) ||
+           (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) ||
+           ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE) ||
+           ext4_verity_in_progress(inode))
+               return;
+
+       WARN_ON_ONCE(!inode_is_locked(inode) &&
+                    !rwsem_is_locked(&inode->i_mapping->invalidate_lock));
+}
+#else
+void ext4_check_map_extents_env(struct inode *inode) {}
+#endif
+
 #define check_block_validity(inode, map)       \
        __check_block_validity((inode), __func__, __LINE__, (map))