btrfs-progs: tune: add --convert-to-free-space-tree option

From the very beginning of free-space-tree feature, we allow mount
option "space_cache=v2" to convert the filesystem to the new feature.

But this is not the proper practice for new features (no matter if it's
incompat or compat_ro).

This is already making the clear_cache/space_cache mount option more
complex.

Thus this patch introduces the proper way to enable free-space-tree, and
I hope one day we can deprecate the "space_cache=" mount option.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2023-05-02 09:01:45 +08:00 committed by David Sterba
parent 6fc223f0a0
commit d4f4d7b76e
5 changed files with 63 additions and 5 deletions

View file

@ -37,6 +37,11 @@ OPTIONS
Convert block groups tracked in standalone block group tree back to Convert block groups tracked in standalone block group tree back to
extent tree and remove 'block-group-tree' feature bit from the filesystem. extent tree and remove 'block-group-tree' feature bit from the filesystem.
--convert-to-free-space-tree
(since kernel 4.5)
Convert to free-space-tree feature (v2 of space cache).
-f -f
Allow dangerous changes, e.g. clear the seeding flag or change fsid. Allow dangerous changes, e.g. clear the seeding flag or change fsid.
Make sure that you are aware of the dangers. Make sure that you are aware of the dangers.

View file

@ -250,7 +250,7 @@ convert_objects = convert/main.o convert/common.o convert/source-fs.o \
mkfs_objects = mkfs/main.o mkfs/common.o mkfs/rootdir.o mkfs_objects = mkfs/main.o mkfs/common.o mkfs/rootdir.o
image_objects = image/main.o image/sanitize.o image_objects = image/main.o image/sanitize.o
tune_objects = tune/main.o tune/seeding.o tune/change-uuid.o tune/change-metadata-uuid.o \ tune_objects = tune/main.o tune/seeding.o tune/change-uuid.o tune/change-metadata-uuid.o \
tune/convert-bgt.o tune/change-csum.o tune/convert-bgt.o tune/change-csum.o check/clear-cache.o
all_objects = $(objects) $(cmds_objects) $(libbtrfs_objects) $(convert_objects) \ all_objects = $(objects) $(cmds_objects) $(libbtrfs_objects) $(convert_objects) \
$(mkfs_objects) $(image_objects) $(tune_objects) $(libbtrfsutil_objects) $(mkfs_objects) $(image_objects) $(tune_objects) $(libbtrfsutil_objects)

View file

@ -35,7 +35,7 @@
*/ */
#define NR_BLOCK_GROUP_CLUSTER (16) #define NR_BLOCK_GROUP_CLUSTER (16)
static int clear_free_space_cache(struct btrfs_fs_info *fs_info) int btrfs_clear_v1_cache(struct btrfs_fs_info *fs_info)
{ {
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_block_group *bg_cache; struct btrfs_block_group *bg_cache;
@ -99,7 +99,7 @@ int do_clear_free_space_cache(struct btrfs_fs_info *fs_info, int clear_version)
warning( warning(
"free space cache v2 detected, use --clear-space-cache v2, proceeding with clearing v1"); "free space cache v2 detected, use --clear-space-cache v2, proceeding with clearing v1");
ret = clear_free_space_cache(fs_info); ret = btrfs_clear_v1_cache(fs_info);
if (ret) { if (ret) {
error("failed to clear free space cache"); error("failed to clear free space cache");
ret = 1; ret = 1;

View file

@ -21,6 +21,7 @@ struct btrfs_fs_info;
struct btrfs_root; struct btrfs_root;
struct task_ctx; struct task_ctx;
int btrfs_clear_v1_cache(struct btrfs_fs_info *fs_info);
int do_clear_free_space_cache(struct btrfs_fs_info *fs_info, int clear_version); int do_clear_free_space_cache(struct btrfs_fs_info *fs_info, int clear_version);
int validate_free_space_cache(struct btrfs_root *root, struct task_ctx *task_ctx); int validate_free_space_cache(struct btrfs_root *root, struct task_ctx *task_ctx);
int truncate_free_ino_items(struct btrfs_root *root); int truncate_free_ino_items(struct btrfs_root *root);

View file

@ -28,6 +28,8 @@
#include "kernel-shared/disk-io.h" #include "kernel-shared/disk-io.h"
#include "kernel-shared/transaction.h" #include "kernel-shared/transaction.h"
#include "kernel-shared/volumes.h" #include "kernel-shared/volumes.h"
#include "kernel-shared/free-space-cache.h"
#include "kernel-shared/free-space-tree.h"
#include "common/utils.h" #include "common/utils.h"
#include "common/open-utils.h" #include "common/open-utils.h"
#include "common/parse-utils.h" #include "common/parse-utils.h"
@ -38,6 +40,7 @@
#include "common/box.h" #include "common/box.h"
#include "cmds/commands.h" #include "cmds/commands.h"
#include "tune/tune.h" #include "tune/tune.h"
#include "check/clear-cache.h"
static char *device; static char *device;
static int force = 0; static int force = 0;
@ -60,6 +63,36 @@ static int set_super_incompat_flags(struct btrfs_root *root, u64 flags)
return ret; return ret;
} }
static int convert_to_fst(struct btrfs_fs_info *fs_info)
{
int ret;
/* We may have invalid old v2 cache, clear them first. */
if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
ret = btrfs_clear_free_space_tree(fs_info);
if (ret < 0) {
errno = -ret;
error("failed to clear stale v2 free space cache: %m");
return ret;
}
}
ret = btrfs_clear_v1_cache(fs_info);
if (ret < 0) {
errno = -ret;
error("failed to clear v1 free space cache: %m");
return ret;
}
ret = btrfs_create_free_space_tree(fs_info);
if (ret < 0) {
errno = -ret;
error("failed to create free space tree: %m");
return ret;
}
pr_verbose(LOG_DEFAULT, "Converted to free space tree feature\n");
return ret;
}
static const char * const tune_usage[] = { static const char * const tune_usage[] = {
"btrfstune [options] device", "btrfstune [options] device",
"Tune settings of filesystem features on an unmounted device", "Tune settings of filesystem features on an unmounted device",
@ -74,6 +107,7 @@ static const char * const tune_usage[] = {
"the separate block-group-tree instead of extent tree (sets the incompat bit)"), "the separate block-group-tree instead of extent tree (sets the incompat bit)"),
OPTLINE("--convert-from-block-group-tree", OPTLINE("--convert-from-block-group-tree",
"convert the block group tree back to extent tree (remove the incompat bit)"), "convert the block group tree back to extent tree (remove the incompat bit)"),
OPTLINE("--convert-to-free-space-tree", "convert filesystem to use free space tree (v2 cache)"),
"", "",
"UUID changes:", "UUID changes:",
OPTLINE("-u", "rewrite fsid, use a random one"), OPTLINE("-u", "rewrite fsid, use a random one"),
@ -108,6 +142,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
int change_metadata_uuid = 0; int change_metadata_uuid = 0;
bool to_extent_tree = false; bool to_extent_tree = false;
bool to_bg_tree = false; bool to_bg_tree = false;
bool to_fst = false;
int csum_type = -1; int csum_type = -1;
char *new_fsid_str = NULL; char *new_fsid_str = NULL;
int ret; int ret;
@ -119,13 +154,16 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
while(1) { while(1) {
enum { GETOPT_VAL_CSUM = GETOPT_VAL_FIRST, enum { GETOPT_VAL_CSUM = GETOPT_VAL_FIRST,
GETOPT_VAL_ENABLE_BLOCK_GROUP_TREE, GETOPT_VAL_ENABLE_BLOCK_GROUP_TREE,
GETOPT_VAL_DISABLE_BLOCK_GROUP_TREE }; GETOPT_VAL_DISABLE_BLOCK_GROUP_TREE,
GETOPT_VAL_ENABLE_FREE_SPACE_TREE };
static const struct option long_options[] = { static const struct option long_options[] = {
{ "help", no_argument, NULL, GETOPT_VAL_HELP}, { "help", no_argument, NULL, GETOPT_VAL_HELP},
{ "convert-to-block-group-tree", no_argument, NULL, { "convert-to-block-group-tree", no_argument, NULL,
GETOPT_VAL_ENABLE_BLOCK_GROUP_TREE}, GETOPT_VAL_ENABLE_BLOCK_GROUP_TREE},
{ "convert-from-block-group-tree", no_argument, NULL, { "convert-from-block-group-tree", no_argument, NULL,
GETOPT_VAL_DISABLE_BLOCK_GROUP_TREE}, GETOPT_VAL_DISABLE_BLOCK_GROUP_TREE},
{ "convert-to-free-space-tree", no_argument, NULL,
GETOPT_VAL_ENABLE_FREE_SPACE_TREE},
#if EXPERIMENTAL #if EXPERIMENTAL
{ "csum", required_argument, NULL, GETOPT_VAL_CSUM }, { "csum", required_argument, NULL, GETOPT_VAL_CSUM },
#endif #endif
@ -175,6 +213,9 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
case GETOPT_VAL_DISABLE_BLOCK_GROUP_TREE: case GETOPT_VAL_DISABLE_BLOCK_GROUP_TREE:
to_extent_tree = true; to_extent_tree = true;
break; break;
case GETOPT_VAL_ENABLE_FREE_SPACE_TREE:
to_fst = true;
break;
#if EXPERIMENTAL #if EXPERIMENTAL
case GETOPT_VAL_CSUM: case GETOPT_VAL_CSUM:
btrfs_warn_experimental( btrfs_warn_experimental(
@ -200,7 +241,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
} }
if (!super_flags && !seeding_flag && !(random_fsid || new_fsid_str) && if (!super_flags && !seeding_flag && !(random_fsid || new_fsid_str) &&
!change_metadata_uuid && csum_type == -1 && !to_bg_tree && !change_metadata_uuid && csum_type == -1 && !to_bg_tree &&
!to_extent_tree) { !to_extent_tree && !to_fst) {
error("at least one option should be specified"); error("at least one option should be specified");
usage(&tune_cmd, 1); usage(&tune_cmd, 1);
return 1; return 1;
@ -269,6 +310,17 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
} }
goto out; goto out;
} }
if (to_fst) {
if (btrfs_fs_compat_ro(root->fs_info, FREE_SPACE_TREE_VALID)) {
error("filesystem already has free-space-tree feature");
ret = 1;
goto out;
}
ret = convert_to_fst(root->fs_info);
if (ret < 0)
error("failed to convert the filesystem to free-space-tree feature");
goto out;
}
if (to_extent_tree) { if (to_extent_tree) {
if (to_bg_tree) { if (to_bg_tree) {
error("option --convert-to-block-group-tree conflicts with --convert-from-block-group-tree"); error("option --convert-to-block-group-tree conflicts with --convert-from-block-group-tree");