From: Dave Chen Date: Mon, 23 Mar 2026 03:43:22 +0000 (+0800) Subject: btrfs: fix unnecessary flush on close when truncating zero-sized files X-Git-Tag: v7.1-rc1~231^2~26 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0e6a169c6487ca3a13d19a9ec6dc9673af5a1cf7;p=thirdparty%2Fkernel%2Flinux.git btrfs: fix unnecessary flush on close when truncating zero-sized files In btrfs_setsize(), when a file is truncated to size 0, the BTRFS_INODE_FLUSH_ON_CLOSE flag is unconditionally set to ensure pending writes get flushed on close. This flag was designed to protect the "truncate-then-rewrite" pattern, where an application truncates a file with existing data down to zero and writes new content, ensuring the new data reach disk on close. However, when a file already has a size of 0 (e.g. a newly created file opened with O_CREAT | O_TRUNC), oldsize and newsize are both 0. In this case, setting BTRFS_INODE_FLUSH_ON_CLOSE is unnecessary because no "good data" was truncated away. The subsequent filemap_flush() in btrfs_release_file() then triggers avoidable writeback that disrupts the normal delayed writeback batching, adding I/O overhead. This comes from a real workload. A backup service creates temporary files via mkstemp(), closes them, and later reopens them with O_TRUNC for writing. The O_TRUNC is defensive. The file creation and usage is done by a different component, so removing the unneeded truncation is not straightforward. This pattern repeats for a large number of files each close() triggers an unnecessary filemap_flush(). Signed-off-by: Dave Chen Signed-off-by: Robbie Ko Reviewed-by: David Sterba Signed-off-by: David Sterba --- diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8d97a8ad3858b..1a4e6a9239aed 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5442,7 +5442,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr) * zero. Make sure any new writes to the file get on disk * on close. */ - if (newsize == 0) + if (newsize == 0 && oldsize != 0) set_bit(BTRFS_INODE_FLUSH_ON_CLOSE, &BTRFS_I(inode)->runtime_flags);