diff --git a/tune/main.c b/tune/main.c index d344cdad06..63539b9915 100644 --- a/tune/main.c +++ b/tune/main.c @@ -126,6 +126,49 @@ static const char * const tune_usage[] = { NULL }; +enum btrfstune_group_enum { + /* Extent/block group tree feature. */ + EXTENT_TREE, + + /* V1/v2 free space cache. */ + SPACE_CACHE, + + /* Metadata UUID. */ + METADATA_UUID, + + /* FSID change. */ + FSID_CHANGE, + + /* Seed device. */ + SEED, + + /* Csum conversion */ + CSUM_CHANGE, + + /* + * Legacy features (which later become default), including: + * - no-holes + * - extref + * - skinny-metadata + */ + LEGACY, + + BTRFSTUNE_NR_GROUPS, +}; + +static bool btrfstune_cmd_groups[BTRFSTUNE_NR_GROUPS] = { 0 }; + +static unsigned int btrfstune_count_set_groups() +{ + int ret = 0; + + for (int i = 0; i < BTRFSTUNE_NR_GROUPS; i++) { + if (btrfstune_cmd_groups[i]) + ret++; + } + return ret; +} + static const struct cmd_struct tune_cmd = { .usagestr = tune_usage }; @@ -135,8 +178,6 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) struct btrfs_root *root; struct btrfs_fs_info *fs_info; unsigned ctree_flags = OPEN_CTREE_WRITES; - int success = 0; - int total = 0; int seeding_flag = 0; u64 seeding_value = 0; int random_fsid = 0; @@ -178,15 +219,19 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) case 'S': seeding_flag = 1; seeding_value = arg_strtou64(optarg); + btrfstune_cmd_groups[SEED] = true; break; case 'r': super_flags |= BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF; + btrfstune_cmd_groups[LEGACY] = true; break; case 'x': super_flags |= BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA; + btrfstune_cmd_groups[LEGACY] = true; break; case 'n': super_flags |= BTRFS_FEATURE_INCOMPAT_NO_HOLES; + btrfstune_cmd_groups[LEGACY] = true; break; case 'f': force = 1; @@ -194,28 +239,35 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) case 'U': ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH; new_fsid_str = optarg; + btrfstune_cmd_groups[FSID_CHANGE] = true; break; case 'u': ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH; random_fsid = 1; + btrfstune_cmd_groups[FSID_CHANGE] = true; break; case 'M': ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH; change_metadata_uuid = 1; new_fsid_str = optarg; + btrfstune_cmd_groups[METADATA_UUID] = true; break; case 'm': ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH; change_metadata_uuid = 1; + btrfstune_cmd_groups[METADATA_UUID] = true; break; case GETOPT_VAL_ENABLE_BLOCK_GROUP_TREE: to_bg_tree = true; + btrfstune_cmd_groups[EXTENT_TREE] = true; break; case GETOPT_VAL_DISABLE_BLOCK_GROUP_TREE: to_extent_tree = true; + btrfstune_cmd_groups[EXTENT_TREE] = true; break; case GETOPT_VAL_ENABLE_FREE_SPACE_TREE: to_fst = true; + btrfstune_cmd_groups[SPACE_CACHE] = true; break; #if EXPERIMENTAL case GETOPT_VAL_CSUM: @@ -223,6 +275,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) "Switching checksums is experimental, do not use for valuable data!"); ctree_flags |= OPEN_CTREE_SKIP_CSUM_CHECK; csum_type = parse_csum_type(optarg); + btrfstune_cmd_groups[CSUM_CHANGE] = true; break; #endif case GETOPT_VAL_HELP: @@ -238,20 +291,23 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) goto free_out; } - if (random_fsid && new_fsid_str) { - error("random fsid can't be used with specified fsid"); + if (btrfstune_count_set_groups() == 0) { + error("at least one option should be specified"); + usage(&tune_cmd, 1); ret = 1; goto free_out; } - if (!super_flags && !seeding_flag && !(random_fsid || new_fsid_str) && - !change_metadata_uuid && csum_type == -1 && !to_bg_tree && - !to_extent_tree && !to_fst) { - error("at least one option should be specified"); + if (btrfstune_count_set_groups() > 1) { + error("too many conflicting options specified"); usage(&tune_cmd, 1); ret = 1; goto free_out; } - + if (random_fsid && new_fsid_str) { + error("random fsid can't be used with specified fsid"); + ret = 1; + goto free_out; + } if (new_fsid_str) { uuid_t tmp; @@ -321,17 +377,17 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) if (to_bg_tree) { if (to_extent_tree) { error("option --convert-to-block-group-tree conflicts with --convert-from-block-group-tree"); - ret = 1; + ret = -EINVAL; goto out; } if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE)) { error("the filesystem already has block group tree feature"); - ret = 1; + ret = -EINVAL; goto out; } if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) { error("the filesystem doesn't have space cache v2, needs to be mounted with \"-o space_cache=v2\" first"); - ret = 1; + ret = -EINVAL; goto out; } ret = convert_to_bg_tree(fs_info); @@ -344,7 +400,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) if (to_fst) { if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) { error("filesystem already has free-space-tree feature"); - ret = 1; + ret = -EINVAL; goto out; } ret = convert_to_fst(fs_info); @@ -355,12 +411,12 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) if (to_extent_tree) { if (to_bg_tree) { error("option --convert-to-block-group-tree conflicts with --convert-from-block-group-tree"); - ret = 1; + ret = -EINVAL; goto out; } if (!btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE)) { error("filesystem doesn't have block-group-tree feature"); - ret = 1; + ret = -EINVAL; goto out; } ret = convert_to_extent_tree(fs_info); @@ -373,7 +429,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) if (seeding_flag) { if (btrfs_fs_incompat(fs_info, METADATA_UUID)) { error("SEED flag cannot be changed on a metadata-uuid changed fs"); - ret = 1; + ret = -EINVAL; goto out; } @@ -383,34 +439,30 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) ret = ask_user("We are going to clear the seeding flag, are you sure?"); if (!ret) { error("clear seeding flag canceled"); - ret = 1; + ret = -EINVAL; goto out; } } ret = update_seeding_flag(root, device, seeding_value, force); - if (!ret) - success++; - total++; + goto out; } if (super_flags) { ret = set_super_incompat_flags(root, super_flags); - if (!ret) - success++; - total++; + goto out; } if (csum_type != -1) { - /* TODO: check conflicting flags */ pr_verbose(LOG_DEFAULT, "Proceed to switch checksums\n"); ret = btrfs_change_csum_type(fs_info, csum_type); + goto out; } if (change_metadata_uuid) { if (seeding_flag) { error("not allowed to set both seeding flag and uuid metadata"); - ret = 1; + ret = -EINVAL; goto out; } @@ -419,10 +471,8 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) else ret = set_metadata_uuid(root, NULL); - if (!ret) - success++; - total++; btrfs_register_all_devices(); + goto out; } if (random_fsid || (new_fsid_str && !change_metadata_uuid)) { @@ -430,7 +480,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) error( "Cannot rewrite fsid while METADATA_UUID flag is active. \n" "Ensure fsid and metadata_uuid match before retrying."); - ret = 1; + ret = -EINVAL; goto out; } @@ -442,24 +492,19 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[]) ret = ask_user("We are going to change UUID, are your sure?"); if (!ret) { error("UUID change canceled"); - ret = 1; + ret = -EINVAL; goto out; } } ret = change_uuid(fs_info, new_fsid_str); - if (!ret) - success++; - total++; + goto out; } - - if (success == total) { - ret = 0; - } else { +out: + if (ret < 0) { fs_info->readonly = 1; ret = 1; error("btrfstune failed"); } -out: close_ctree(root); btrfs_close_all_devices();