]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ext4: use reserved metadata blocks when splitting extent on endio
authorZhang Yi <yi.zhang@huawei.com>
Mon, 5 Jan 2026 01:45:16 +0000 (09:45 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 20 Jan 2026 03:28:30 +0000 (22:28 -0500)
When performing buffered writes, we may need to split and convert an
unwritten extent into a written one during the end I/O process. However,
we do not reserve space specifically for these metadata changes, we only
reserve 2% of space or 4096 blocks. To address this, we use
EXT4_GET_BLOCKS_PRE_IO to potentially split extents in advance and
EXT4_GET_BLOCKS_METADATA_NOFAIL to utilize reserved space if necessary.

These two approaches can reduce the likelihood of running out of space
and losing data. However, these methods are merely best efforts, we
could still run out of space, and there is not much difference between
converting an extent during the writeback process and the end I/O
process, it won't increase the risk of losing data if we postpone the
conversion.

Therefore, also use EXT4_GET_BLOCKS_METADATA_NOFAIL in
ext4_convert_unwritten_extents_endio() to prepare for the buffered I/O
iomap conversion, which may perform extent conversion during the end I/O
process.

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Baokun Li <libaokun1@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://patch.msgid.link/20260105014522.1937690-2-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/extents.c

index e0295e0339b496640786cdeee5e38cd0e70d966b..671cb038a4179f1111520c17801ce4212211b87e 100644 (file)
@@ -3794,6 +3794,8 @@ ext4_convert_unwritten_extents_endio(handle_t *handle, struct inode *inode,
         * illegal.
         */
        if (ee_block != map->m_lblk || ee_len > map->m_len) {
+               int flags = EXT4_GET_BLOCKS_CONVERT |
+                           EXT4_GET_BLOCKS_METADATA_NOFAIL;
 #ifdef CONFIG_EXT4_DEBUG
                ext4_warning(inode->i_sb, "Inode (%ld) finished: extent logical block %llu,"
                             " len %u; IO logical block %llu, len %u",
@@ -3801,7 +3803,7 @@ ext4_convert_unwritten_extents_endio(handle_t *handle, struct inode *inode,
                             (unsigned long long)map->m_lblk, map->m_len);
 #endif
                path = ext4_split_convert_extents(handle, inode, map, path,
-                                               EXT4_GET_BLOCKS_CONVERT, NULL);
+                                                 flags, NULL);
                if (IS_ERR(path))
                        return path;