From 59615e2c1f63dfd65f74c166e803873d3362e51a Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 6 Jan 2026 13:20:30 +1030 Subject: [PATCH] btrfs: reject single block sized compression early Currently for an inode that needs compression, even if there is a delalloc range that is single fs block sized and can not be inlined, we will still go through the compression path. Then inside compress_file_range(), we have one extra check to reject single block sized range, and fall back to regular uncompressed write. This rejection is in fact a little too late, we have already allocated memory to async_chunk, delayed the submission, just to fallback to the same uncompressed write. Change the behavior to reject such cases earlier at inode_need_compress(), so for such single block sized range we won't even bother trying to go through compress path. And since the inline small block check is inside inode_need_compress() and compress_file_range() also calls that function, we no longer need a dedicate check inside compress_file_range(). Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 247b373bf5cf0..be47aa58e944e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -816,6 +816,13 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start, return 0; } + /* + * If the delalloc range is only one fs block and can not be inlined, + * do not even bother try compression, as there will be no space saving + * and will always fallback to regular write later. + */ + if (start != 0 && end + 1 - start <= fs_info->sectorsize) + return 0; /* Defrag ioctl takes precedence over mount options and properties. */ if (inode->defrag_compress == BTRFS_DEFRAG_DONT_COMPRESS) return 0; @@ -953,18 +960,7 @@ again: if (actual_end <= start) goto cleanup_and_bail_uncompressed; - total_compressed = actual_end - start; - - /* - * Skip compression for a small file range(<=blocksize) that - * isn't an inline extent, since it doesn't save disk space at all. - */ - if (total_compressed <= blocksize && - (start > 0 || end + 1 < inode->disk_i_size)) - goto cleanup_and_bail_uncompressed; - - total_compressed = min_t(unsigned long, total_compressed, - BTRFS_MAX_UNCOMPRESSED); + total_compressed = min_t(unsigned long, actual_end - start, BTRFS_MAX_UNCOMPRESSED); total_in = 0; ret = 0; -- 2.47.3