summaryrefslogtreecommitdiff
path: root/fs/ext4
diff options
context:
space:
mode:
authorZhang Yi <yi.zhang@huawei.com>2026-01-05 09:45:16 +0800
committerSasha Levin <sashal@kernel.org>2026-03-04 07:20:26 -0500
commit43aecb9bab1a97a13ac0ec4f153f6a28f0270d4c (patch)
tree7a7d59ef987298003fdc6682250f4541109b2db5 /fs/ext4
parentb74cb608f619445637106ec44612a957cea9ba2a (diff)
downloadlinux-43aecb9bab1a97a13ac0ec4f153f6a28f0270d4c.tar.gz
linux-43aecb9bab1a97a13ac0ec4f153f6a28f0270d4c.tar.bz2
linux-43aecb9bab1a97a13ac0ec4f153f6a28f0270d4c.zip
ext4: use reserved metadata blocks when splitting extent on endio
[ Upstream commit 01942af95ab6c9d98e64ae01fdc243a03e4b973f ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/extents.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 18b39eed7526..418c4351ef40 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3809,6 +3809,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",
@@ -3816,7 +3818,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;