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