From: Qu Wenruo Date: Mon, 9 Feb 2026 00:21:09 +0000 (+1030) Subject: btrfs: fix the inline compressed extent check in inode_need_compress() X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=883adb6dcff0f96dbbdb6488842a38b121ebd68c;p=thirdparty%2Fkernel%2Flinux.git btrfs: fix the inline compressed extent check in inode_need_compress() [BUG] Since commit 59615e2c1f63 ("btrfs: reject single block sized compression early"), the following script will result the inode to have NOCOMPRESS flag, meanwhile old kernels don't: # mkfs.btrfs -f $dev # mount $dev $mnt -o max_inline=2k,compress=zstd # truncate -s 8k $mnt/foobar # xfs_io -f -c "pwrite 0 2k" $mnt/foobar # sync Before that commit, the inode will not have NOCOMPRESS flag: item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160 generation 9 transid 9 size 8192 nbytes 4096 block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0 sequence 3 flags 0x0(none) But after that commit, the inode will have NOCOMPRESS flag: item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160 generation 9 transid 10 size 8192 nbytes 4096 block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0 sequence 3 flags 0x8(NOCOMPRESS) This will make a lot of files no longer to be compressed. [CAUSE] The old compressed inline check looks like this: if (total_compressed <= blocksize && (start > 0 || end + 1 < inode->disk_i_size)) goto cleanup_and_bail_uncompressed; That inline part check is equal to "!(start == 0 && end + 1 >= inode->disk_i_size)", but the new check no longer has that disk_i_size check. Thus it means any single block sized write at file offset 0 will pass the inline check, which is wrong. Furthermore, since we have merged the old check into inode_need_compress(), there is no disk_i_size based inline check anymore, we will always try compressing that single block at file offset 0, then later find out it's not a net win and go to the mark_incompressible tag. This results the inode to have NOCOMPRESS flag. [FIX] Add back the missing disk_i_size based check into inode_need_compress(). Now the same script will no longer cause NOCOMPRESS flag. Fixes: 59615e2c1f63 ("btrfs: reject single block sized compression early") Reported-by: Chris Mason Link: https://lore.kernel.org/linux-btrfs/20260208183840.975975-1-clm@meta.com/ Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f643a05208720..a4ad37fd65fbe 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -811,7 +811,8 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start, * 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) + if (end + 1 - start <= fs_info->sectorsize && + (start > 0 || end + 1 < inode->disk_i_size)) return 0; /* Defrag ioctl takes precedence over mount options and properties. */ if (inode->defrag_compress == BTRFS_DEFRAG_DONT_COMPRESS)