f2fs: fix to mitigate overhead of f2fs_zero_post_eof_page()

[ Upstream commit c2f7c32b254006ad48f8e4efb2e7e7bf71739f17 ]

f2fs_zero_post_eof_page() may cuase more overhead due to invalidate_lock
and page lookup, change as below to mitigate its overhead:
- check new_size before grabbing invalidate_lock
- lookup and invalidate pages only in range of [old_size, new_size]

Fixes: ba8dac350faf ("f2fs: fix to zero post-eof page")
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Chao Yu
2025-09-16 10:47:09 +08:00
committed by Greg Kroah-Hartman
parent 83a8e4efea
commit 7d9b97e613

View File

@@ -36,15 +36,23 @@
#include <trace/events/f2fs.h>
#include <uapi/linux/f2fs.h>
static void f2fs_zero_post_eof_page(struct inode *inode, loff_t new_size)
static void f2fs_zero_post_eof_page(struct inode *inode,
loff_t new_size, bool lock)
{
loff_t old_size = i_size_read(inode);
if (old_size >= new_size)
return;
if (mapping_empty(inode->i_mapping))
return;
if (lock)
filemap_invalidate_lock(inode->i_mapping);
/* zero or drop pages only in range of [old_size, new_size] */
truncate_pagecache(inode, old_size);
truncate_inode_pages_range(inode->i_mapping, old_size, new_size);
if (lock)
filemap_invalidate_unlock(inode->i_mapping);
}
static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
@@ -115,9 +123,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
filemap_invalidate_lock(inode->i_mapping);
f2fs_zero_post_eof_page(inode, (folio->index + 1) << PAGE_SHIFT);
filemap_invalidate_unlock(inode->i_mapping);
f2fs_zero_post_eof_page(inode, (folio->index + 1) << PAGE_SHIFT, true);
file_update_time(vmf->vma->vm_file);
filemap_invalidate_lock_shared(inode->i_mapping);
@@ -1077,7 +1083,7 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
filemap_invalidate_lock(inode->i_mapping);
if (attr->ia_size > old_size)
f2fs_zero_post_eof_page(inode, attr->ia_size);
f2fs_zero_post_eof_page(inode, attr->ia_size, false);
truncate_setsize(inode, attr->ia_size);
if (attr->ia_size <= old_size)
@@ -1196,9 +1202,7 @@ static int f2fs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
if (ret)
return ret;
filemap_invalidate_lock(inode->i_mapping);
f2fs_zero_post_eof_page(inode, offset + len);
filemap_invalidate_unlock(inode->i_mapping);
f2fs_zero_post_eof_page(inode, offset + len, true);
pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
@@ -1484,7 +1488,7 @@ static int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
filemap_invalidate_lock(inode->i_mapping);
f2fs_zero_post_eof_page(inode, offset + len);
f2fs_zero_post_eof_page(inode, offset + len, false);
f2fs_lock_op(sbi);
f2fs_drop_extent_tree(inode);
@@ -1608,9 +1612,7 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
if (ret)
return ret;
filemap_invalidate_lock(mapping);
f2fs_zero_post_eof_page(inode, offset + len);
filemap_invalidate_unlock(mapping);
f2fs_zero_post_eof_page(inode, offset + len, true);
pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
@@ -1744,7 +1746,7 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
filemap_invalidate_lock(mapping);
f2fs_zero_post_eof_page(inode, offset + len);
f2fs_zero_post_eof_page(inode, offset + len, false);
truncate_pagecache(inode, offset);
while (!ret && idx > pg_start) {
@@ -1800,9 +1802,7 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
if (err)
return err;
filemap_invalidate_lock(inode->i_mapping);
f2fs_zero_post_eof_page(inode, offset + len);
filemap_invalidate_unlock(inode->i_mapping);
f2fs_zero_post_eof_page(inode, offset + len, true);
f2fs_balance_fs(sbi, true);
@@ -4718,9 +4718,8 @@ static ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from)
if (err)
return err;
filemap_invalidate_lock(inode->i_mapping);
f2fs_zero_post_eof_page(inode, iocb->ki_pos + iov_iter_count(from));
filemap_invalidate_unlock(inode->i_mapping);
f2fs_zero_post_eof_page(inode,
iocb->ki_pos + iov_iter_count(from), true);
return count;
}