From cc337324cc6be1ce0ae7e5a068dcb7e99ae1b59c Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 14 Sep 2026 18:11:30 +0100 Subject: [PATCH] btrfs: fix creation of compressed inline extents that don't save space If the compressed data of an inline extent is larger than or equals to the size of the uncompressed data, we are still allowing the creation of the compressed inline extent, which does not result in any benefits, quite the contrary as we waste metadata space and have to decompress when reading. This is a recent regression introduced in commit 3eaf5f082c4c ("btrfs: extract inlined creation into a dedicated delalloc helper"). It happens because we are passing the block size to btrfs_compress_bio(), so we don't get -E2BIG from the compression code anymore, but we can not pass i_size either, because if i_size is smaller than sector size, we end up never creating lzo compressed inline extent for such small i_size values. So refuse the compressed result at run_delalloc_inline() if its size is not smaller than the uncompressed size (i_size). Reported-by: Hanabishi Link: https://lore.kernel.org/linux-btrfs/c97652a5-ac6b-4de6-aa23-3cdebc01d00b@gmail.com/ Fixes: 3eaf5f082c4c ("btrfs: extract inlined creation into a dedicated delalloc helper") CC: stable@vger.kernel.org # 7.1+ Reviewed-by: Qu Wenruo Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/inode.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3668cbc7598e..4f976b52996d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2339,12 +2339,27 @@ static int run_delalloc_inline(struct btrfs_inode *inode, struct folio *locked_f } else if (inode->prop_compress) { compress_type = inode->prop_compress; } + /* + * We need to pass blocksize and not i_size, otherwise we can't + * create compressed inline extents for data smaller than sector + * size with lzo. + */ cb = btrfs_compress_bio(inode, 0, blocksize, compress_type, compress_level, 0); if (IS_ERR(cb)) { cb = NULL; /* Just fall back to non-compressed case. */ } else { compressed_size = cb->bbio.bio.bi_iter.bi_size; + /* + * If we did not save space, it's pointless and wasteful + * to have an inline compressed extent, so fallback to + * an uncompressed inline extent. + */ + if (compressed_size >= i_size) { + cleanup_compressed_bio(cb); + cb = NULL; + compressed_size = 0; + } } } if (!can_cow_file_range_inline(inode, 0, i_size, compressed_size)) {