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.