]> git.hungrycats.org Git - linux/commit
btrfs: raid56: say whether a metadata read-modify-write is a write hole
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Wed, 5 Aug 2026 22:15:06 +0000 (18:15 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Wed, 16 Sep 2026 21:40:02 +0000 (17:40 -0400)
commit510812f8fbf8f56af7d5a8504811225bcfa12522
tree27cfb731aef8d0cab79087961856070fa9a9cb5d
parentfac1ef7207bab04f4160ae0aa4c64f29aece7bf5
btrfs: raid56: say whether a metadata read-modify-write is a write hole

meta_rmw counts sub-stripe metadata writes, which is a proxy for exposure
rather than a measurement of it.  A stripe modified in place is only a write
hole if it holds data some completed transaction is relying on; a stripe
that two writes of the *same* transaction happen to split costs an extra
read but risks nothing, because a tear loses that whole transaction anyway.
The counter cannot tell those apart, so it cannot answer the only question
that matters.

The rbio can.  A read-modify-write has already read every column the write
does not cover, so at the point of the report it is holding the stripe's
on-disk contents.  Walk the uncovered tree block positions and read their
headers: a block whose bytenr and fsid match belongs there, and its
generation says which transaction put it there.  Compare that against the
generation of the blocks this write is carrying, taken from the same rbio,
so a transaction committing concurrently cannot skew the verdict:

  meta_rmw_cur   the same transaction's own blocks -- a cost
  meta_rmw_old   an earlier transaction's -- a write hole
  meta_rmw_free  no tree block there at all

System block groups are classified too, not just metadata ones.  A system
chunk carries no METADATA bit, so a flags test excludes it, but it holds
the chunk tree: the same tree block header, the same generation field, and
a worse consequence if a degraded crash tears it, since without the chunk
tree no logical address can be mapped at all.  meta_rmw already counted
system chunks; only the classification skipped them, so their read-modify-
writes were visible as a rate and never as a verdict.  Whether a raid56
system chunk ever rewrites parity over a committed tree block is therefore
an open question that this answers by measurement rather than by reasoning
about how the chunk tree is laid out.

This trusts nothing the allocator says about itself.  The stripe runs, the
liveness map and the drain accounting are all bookkeeping that could be
wrong in the same way twice; the header in the sector is what a degraded
read would actually have to reconstruct.

On a 3-device raid5 filesystem with raid5 metadata, 6000 small files with
periodic syncs and then a third rewritten, plain stripe_alloc reports 249
sub-stripe metadata writes of which 174 rewrite parity over committed tree
blocks.  Adding stripe_meta leaves 37 sub-stripe writes and none of them.

Assisted-by: Claude:claude-fable-5
fs/btrfs/fs.h
fs/btrfs/raid56.c
fs/btrfs/sysfs.c