btrfs: bug report: reflink racing with async compression forces read-only
Qu Wenruo
quwenruo.btrfs at gmx.com
Wed Nov 4 13:02:41 PST 2026
在 2026/11/4 22:40, Breno Leitao 写道:
> Hi,
>
> We are seeing btrfs go read-only on arm64 production hosts (64K pages,
> 4K blocks, compress-force=zstd:3), on 6.16-based kernels and up, still
> being reproduced in linux-next as of today:
>
> BTRFS warning (device nvme0n1p2): no extent map found for inode ...
> when unpinning extent range [20480, 24576), generation ...
> BTRFS: error (device nvme0n1p2 state A) in btrfs_finish_one_ordered:3200:
> errno=-2 No such entry
> BTRFS info (device nvme0n1p2 state EA): forced readonly
>
> A quick bissection seems to point to commit 1d2fbb7f1f9e ("btrfs: allow
> compression even if the range is not page aligned")
>
> I've able to come up with a reproducer that hits the issue within
> seconds with 64K pages:
>
> https://github.com/leitao/btrfs-reflink-async-compress
Thanks for the report.
>
> My robot identified this as the root cause, but I am not smart enough to
> understand:
>
> A reflink into a range that is still being compressed does not wait
> for it:
>
> 1. Another part of the same folio starts writeback first, which clears
> the folio's dirty tag.
This shouldn't happen, as btrfs has per-block dirty tracking, thus the
PAGECACHE_TAG_DIRTY should only be cleared when the last dirty block got
its dirty flag cleared.
It looks like some part of code doesn't properly handling the folio
PAGECACHE_TAG* in a per-block way.
Thankfully you have a reproducer, it should greatly speedup the fix.
And thank you again for doing a proper bug report, instead of creating
LLM slop without understanding it.
A lot of guys should really adapt your style of bug reporting.
Thanks,
Qu
> 2. The second filemap_fdatawrite_range() in btrfs_fdatawrite_range()
> finds folios by that tag, so btrfs_wait_ordered_range() returns
> before the async extent has an ordered extent.
> 3. btrfs_clone() drops or splits the extent map pinned for that extent,
> and the transaction aborts when it completes. If the clone wins the
> race instead, the compressed write lands after it and the cloned data
> is silently lost.
>
> Thanks,
> --breno
More information about the linux-arm-kernel
mailing list