]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
btrfs: do not touch page cache for encoded writes
authorQu Wenruo <wqu@suse.com>
Thu, 19 Feb 2026 08:21:12 +0000 (18:51 +1030)
committerDavid Sterba <dsterba@suse.com>
Tue, 17 Mar 2026 10:43:07 +0000 (11:43 +0100)
[BUG]
When running btrfs/284, the following ASSERT() will be triggered with
64K page size and 4K fs block size:

  assertion failed: folio_test_writeback(folio) :: 0, in subpage.c:476
  ------------[ cut here ]------------
  kernel BUG at subpage.c:476!
  Internal error: Oops - BUG: 00000000f2000800 [#1]  SMP
  CPU: 4 UID: 0 PID: 2313 Comm: kworker/u37:2 Tainted: G           OE       6.19.0-rc8-custom+ #185 PREEMPT(voluntary)
  Hardware name: QEMU KVM Virtual Machine, BIOS unknown 2/2/2022
  Workqueue: btrfs-endio simple_end_io_work [btrfs]
  pc : btrfs_subpage_clear_writeback+0x148/0x160 [btrfs]
  lr : btrfs_subpage_clear_writeback+0x148/0x160 [btrfs]
  Call trace:
   btrfs_subpage_clear_writeback+0x148/0x160 [btrfs] (P)
   btrfs_folio_clamp_clear_writeback+0xb4/0xd0 [btrfs]
   end_compressed_writeback+0xe0/0x1e0 [btrfs]
   end_bbio_compressed_write+0x1e8/0x218 [btrfs]
   btrfs_bio_end_io+0x108/0x258 [btrfs]
   simple_end_io_work+0x68/0xa8 [btrfs]
   process_one_work+0x168/0x3f0
   worker_thread+0x25c/0x398
   kthread+0x154/0x250
   ret_from_fork+0x10/0x20
  ---[ end trace 0000000000000000 ]---

[CAUSE]
The offending bio is from an encoded write, where the compressed data is
directly written as a data extent, without touching the page cache.

However the encoded write still utilizes the regular buffered write path
for compressed data, by setting the compressed_bio::writeback flag.

When that flag is set, at end_bbio_compressed_write() btrfs will go
clearing the writeback flag of the folios in the page cache.

However for bs < ps cases, the subpage helper has one extra check to make
sure the folio has a writeback flag set in the first place.

But since it's an encoded write, we never go through page
cache, thus the folio has no writeback flag and triggers the ASSERT().

[FIX]
Do not set compressed_bio::writeback flag for encoded writes, and change
the ASSERT() in btrfs_submit_compressed_write() to make sure that flag
is not set.

Fixes: e1bc83f8b157 ("btrfs: get rid of compressed_folios[] usage for encoded writes")
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/compression.c

index ac995ec78e0574cba957218b6b63701a7142e5fa..dc61f7e3cbbf37dd766cd4df9c644773d0691c55 100644 (file)
@@ -320,7 +320,12 @@ void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
 
        ASSERT(IS_ALIGNED(ordered->file_offset, fs_info->sectorsize));
        ASSERT(IS_ALIGNED(ordered->num_bytes, fs_info->sectorsize));
-       ASSERT(cb->writeback);
+       /*
+        * This flag determines if we should clear the writeback flag from the
+        * page cache. But this function is only utilized by encoded writes, it
+        * never goes through the page cache.
+        */
+       ASSERT(!cb->writeback);
 
        cb->start = ordered->file_offset;
        cb->len = ordered->num_bytes;
@@ -346,8 +351,7 @@ struct compressed_bio *btrfs_alloc_compressed_write(struct btrfs_inode *inode,
        cb = alloc_compressed_bio(inode, start, REQ_OP_WRITE, end_bbio_compressed_write);
        cb->start = start;
        cb->len = len;
-       cb->writeback = true;
-
+       cb->writeback = false;
        return cb;
 }