inc_block_group_ro(cache, true);
}
+ /*
+ * The mount options rule out space_cache=v1, but the cache format can
+ * only be changed at mount, so a filesystem can arrive here with cache
+ * inodes still on disk while the options say otherwise. Those inodes
+ * are nodatacow and preallocated: whatever writes them next writes in
+ * place. Refuse rather than hope nothing does.
+ */
+ if (btrfs_test_opt(info, STRIPE_ALLOC) &&
+ btrfs_free_space_cache_v1_present(info)) {
+ btrfs_err(info,
+"stripe_alloc is not supported while a v1 space cache is present on disk; mount once without stripe_alloc to clear it (-o clear_cache, or space_cache=v2)");
+ ret = -EINVAL;
+ goto error;
+ }
+
btrfs_init_global_block_rsv(info);
ret = check_chunk_block_group_mappings(info);
error:
if (!btrfs_test_opt(fs_info, SPACE_CACHE))
return;
+ /*
+ * The v1 cache inode is nodatacow and preallocated: its blocks are
+ * overwritten in place during commit. That is exactly the write this
+ * allocator exists to prevent, and the cache carries no csums, so a
+ * torn stripe would be undetectable afterwards. stripe_alloc requires
+ * the free space tree at mount, so this should be unreachable -- but
+ * remount rewrites the cache options after validating them (see
+ * btrfs_reconfigure()), so refuse here as well rather than trust that.
+ */
+ if (btrfs_test_opt(fs_info, STRIPE_ALLOC)) {
+ btrfs_warn_rl(fs_info,
+"not writing the v1 space cache for block group %llu: stripe_alloc is enabled",
+ block_group->start);
+ return;
+ }
+
/*
* If this block group is smaller than 100 megs don't bother caching the
* block group.
return btrfs_super_cache_generation(fs_info->super_copy);
}
+/*
+ * Is a v1 free space cache present on disk?
+ *
+ * btrfs_free_space_cache_v1_active() reads the superblock's
+ * cache_generation, which says whether the last mount wrote the cache, not
+ * whether the cache is there. The cache inodes themselves are the durable
+ * evidence, so look for one: they live in the tree root under
+ * BTRFS_FREE_SPACE_OBJECTID, keyed by block group start.
+ *
+ * Returns false if the tree cannot be searched; callers use this to refuse
+ * an option, and failing a mount because the answer was unavailable would
+ * be worse than the risk it guards against.
+ */
+bool btrfs_free_space_cache_v1_present(struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_root *root = fs_info->tree_root;
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ struct btrfs_key found_key;
+ bool present = false;
+ int ret;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return false;
+
+ key.objectid = BTRFS_FREE_SPACE_OBJECTID;
+ key.type = 0;
+ key.offset = 0;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0)
+ goto out;
+ if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret)
+ goto out;
+ }
+ btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
+ present = (found_key.objectid == BTRFS_FREE_SPACE_OBJECTID);
+out:
+ btrfs_free_path(path);
+ return present;
+}
+
static int cleanup_free_space_cache_v1(struct btrfs_fs_info *fs_info,
struct btrfs_trans_handle *trans)
{
void btrfs_trim_fully_remapped_block_group(struct btrfs_block_group *bg);
bool btrfs_free_space_cache_v1_active(struct btrfs_fs_info *fs_info);
+bool btrfs_free_space_cache_v1_present(struct btrfs_fs_info *fs_info);
int btrfs_set_free_space_cache_v1_active(struct btrfs_fs_info *fs_info, bool active);
/* Support functions for running our sanity tests */
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
}
if (btrfs_raw_test_opt(*mount_opt, STRIPE_ALLOC)) {
- if (!btrfs_raw_test_opt(*mount_opt, FREE_SPACE_TREE)) {
+ /*
+ * Only v1 is a problem: its cache inode is nodatacow and
+ * preallocated, so the cache is overwritten in place during
+ * commit -- a sub-stripe write into a data block group, into
+ * whatever committed stripes the cache occupies, and nodatasum
+ * so nothing would show the damage afterwards. The free space
+ * tree and no cache at all are both fine; nothing here needs
+ * either one.
+ */
+ if (btrfs_raw_test_opt(*mount_opt, SPACE_CACHE)) {
btrfs_err(info,
- "stripe_alloc requires the free space tree (space_cache=v2)");
+ "stripe_alloc is not supported with space_cache=v1");
ret = false;
}
if (btrfs_fs_incompat(info, REMAP_TREE)) {
}
}
+ /*
+ * The block above rewrites the cache options to match the disk after
+ * btrfs_check_options() has already had its say -- it has to, because
+ * the cache format can only be converted at mount, never at remount.
+ * So whatever it decides is what we run with, and nothing re-examines
+ * stripe_alloc against it. Re-check what we actually ended up with.
+ */
+ if (btrfs_test_opt(fs_info, STRIPE_ALLOC) &&
+ btrfs_test_opt(fs_info, SPACE_CACHE)) {
+ btrfs_err(fs_info,
+"stripe_alloc is not supported with space_cache=v1, which this filesystem is still using");
+ ret = -EINVAL;
+ goto restore;
+ }
+
ret = 0;
if (!sb_rdonly(sb) && (fc->sb_flags & SB_RDONLY))
ret = btrfs_remount_ro(fs_info);