]> git.hungrycats.org Git - linux/commit
btrfs: stripe_alloc: refuse space_cache=v1
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Wed, 5 Aug 2026 03:33:32 +0000 (23:33 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Wed, 16 Sep 2026 21:40:00 +0000 (17:40 -0400)
commitaeeaf9daa8d743ba29e58397d39989cbdf19b406
treebf3501766c8786af1fedb4830df507dc5347a0ce
parent298233e996fde46d5c9bdafe05b1550b4c1fe232
btrfs: stripe_alloc: refuse space_cache=v1

The v1 free space cache inode is nodatacow, preallocated and nodatasum,
so the cache is overwritten in place during commit: a sub-stripe write
into a data block group, landing in whatever committed stripes the cache
occupies, with no csum that could reveal the damage afterwards.  That is
precisely the write this series exists to prevent.

The free space tree is not what stripe_alloc needs -- nothing in it reads
the tree, and the by-size index it allocates from is the in-memory free
space, which exists whatever the on-disk format is.  Having no cache at
all is fine too.  Only v1 has to be kept away, so say that instead of
demanding v2.

Three places, because the cache format can only be converted at mount and
never at remount, so the option alone is not the whole story:

 - btrfs_check_mountopts() rejects space_cache=v1 with stripe_alloc.

 - btrfs_reconfigure() rewrites the cache options after that validation,
   to restore what is on disk.  It has to, given the above.  Re-check
   afterwards rather than assume the options still mean what they did.

 - block group read time refuses to mount when v1 cache inodes are
   present on disk at all.  cache_generation only records whether the
   last mount wrote the cache; the inodes are the durable evidence, so
   btrfs_free_space_cache_v1_present() looks for one under
   BTRFS_FREE_SPACE_OBJECTID in the tree root.  Clearing them is one
   mount away, and the error message says so.

cache_save_setup() also declines to set the cache up while stripe_alloc
is on.  The checks above should make that unreachable, but it is the
point where the in-place write would actually be issued.

Assisted-by: Claude:claude-fable-5
fs/btrfs/block-group.c
fs/btrfs/free-space-cache.c
fs/btrfs/free-space-cache.h
fs/btrfs/super.c