"Fossies" - the Fresh Open Source Software Archive

Member "btrfs-progs-v5.4/btrfstune.c" (3 Dec 2019, 18386 Bytes) of package /linux/misc/btrfs-progs-v5.4.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "btrfstune.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: v5.1.1_vs_v5.2.

    1 /*
    2  * Copyright (C) 2008 Oracle.  All rights reserved.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public
    6  * License v2 as published by the Free Software Foundation.
    7  *
    8  * This program is distributed in the hope that it will be useful,
    9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11  * General Public License for more details.
   12  *
   13  * You should have received a copy of the GNU General Public
   14  * License along with this program; if not, write to the
   15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   16  * Boston, MA 021110-1307, USA.
   17  */
   18 
   19 #include <stdio.h>
   20 #include <stdlib.h>
   21 #include <sys/types.h>
   22 #include <sys/stat.h>
   23 #include <fcntl.h>
   24 #include <unistd.h>
   25 #include <dirent.h>
   26 #include <uuid/uuid.h>
   27 #include <getopt.h>
   28 
   29 #include "kerncompat.h"
   30 #include "ctree.h"
   31 #include "disk-io.h"
   32 #include "transaction.h"
   33 #include "common/utils.h"
   34 #include "volumes.h"
   35 #include "common/help.h"
   36 #include "common/box.h"
   37 
   38 static char *device;
   39 static int force = 0;
   40 
   41 static int update_seeding_flag(struct btrfs_root *root, int set_flag)
   42 {
   43     struct btrfs_trans_handle *trans;
   44     struct btrfs_super_block *disk_super;
   45     u64 super_flags;
   46     int ret;
   47 
   48     disk_super = root->fs_info->super_copy;
   49     super_flags = btrfs_super_flags(disk_super);
   50     if (set_flag) {
   51         if (super_flags & BTRFS_SUPER_FLAG_SEEDING) {
   52             if (force)
   53                 return 0;
   54             else
   55                 warning("seeding flag is already set on %s",
   56                         device);
   57             return 1;
   58         }
   59         super_flags |= BTRFS_SUPER_FLAG_SEEDING;
   60     } else {
   61         if (!(super_flags & BTRFS_SUPER_FLAG_SEEDING)) {
   62             warning("seeding flag is not set on %s", device);
   63             return 1;
   64         }
   65         super_flags &= ~BTRFS_SUPER_FLAG_SEEDING;
   66         warning("seeding flag cleared on %s", device);
   67     }
   68 
   69     trans = btrfs_start_transaction(root, 1);
   70     BUG_ON(IS_ERR(trans));
   71     btrfs_set_super_flags(disk_super, super_flags);
   72     ret = btrfs_commit_transaction(trans, root);
   73 
   74     return ret;
   75 }
   76 
   77 /*
   78  * Return 0 for no unfinished fsid change.
   79  * Return >0 for unfinished fsid change, and restore unfinished fsid/
   80  * chunk_tree_id into fsid_ret/chunk_id_ret.
   81  */
   82 static int check_unfinished_fsid_change(struct btrfs_fs_info *fs_info,
   83                     uuid_t fsid_ret, uuid_t chunk_id_ret)
   84 {
   85     struct btrfs_root *tree_root = fs_info->tree_root;
   86     u64 flags = btrfs_super_flags(fs_info->super_copy);
   87 
   88     if (flags & (BTRFS_SUPER_FLAG_CHANGING_FSID |
   89              BTRFS_SUPER_FLAG_CHANGING_FSID_V2)) {
   90         memcpy(fsid_ret, fs_info->super_copy->fsid, BTRFS_FSID_SIZE);
   91         read_extent_buffer(tree_root->node, chunk_id_ret,
   92                 btrfs_header_chunk_tree_uuid(tree_root->node),
   93                 BTRFS_UUID_SIZE);
   94         return 1;
   95     }
   96     return 0;
   97 }
   98 
   99 static int set_metadata_uuid(struct btrfs_root *root, const char *uuid_string)
  100 {
  101     struct btrfs_super_block *disk_super;
  102     uuid_t new_fsid, unused1, unused2;
  103     struct btrfs_trans_handle *trans;
  104     bool new_uuid = true;
  105     u64 incompat_flags;
  106     bool uuid_changed;
  107     u64 super_flags;
  108     int ret;
  109 
  110     disk_super = root->fs_info->super_copy;
  111     super_flags = btrfs_super_flags(disk_super);
  112     incompat_flags = btrfs_super_incompat_flags(disk_super);
  113     uuid_changed = incompat_flags & BTRFS_FEATURE_INCOMPAT_METADATA_UUID;
  114 
  115     if (super_flags & BTRFS_SUPER_FLAG_SEEDING) {
  116         fprintf(stderr, "cannot set metadata UUID on a seed device\n");
  117         return 1;
  118     }
  119 
  120     if (check_unfinished_fsid_change(root->fs_info, unused1, unused2)) {
  121         fprintf(stderr,
  122             "UUID rewrite in progress, cannot change fsid\n");
  123         return 1;
  124     }
  125 
  126     if (uuid_string)
  127         uuid_parse(uuid_string, new_fsid);
  128     else
  129         uuid_generate(new_fsid);
  130 
  131     new_uuid = (memcmp(new_fsid, disk_super->fsid, BTRFS_FSID_SIZE) != 0);
  132 
  133     /* Step 1 sets the in progress flag */
  134     trans = btrfs_start_transaction(root, 1);
  135     super_flags |= BTRFS_SUPER_FLAG_CHANGING_FSID_V2;
  136     btrfs_set_super_flags(disk_super, super_flags);
  137     ret = btrfs_commit_transaction(trans, root);
  138     if (ret < 0)
  139         return ret;
  140 
  141     if (new_uuid && uuid_changed && memcmp(disk_super->metadata_uuid,
  142                            new_fsid, BTRFS_FSID_SIZE) == 0) {
  143         /*
  144          * Changing fsid to be the same as metadata uuid, so just
  145          * disable the flag
  146          */
  147         memcpy(disk_super->fsid, &new_fsid, BTRFS_FSID_SIZE);
  148         incompat_flags &= ~BTRFS_FEATURE_INCOMPAT_METADATA_UUID;
  149         btrfs_set_super_incompat_flags(disk_super, incompat_flags);
  150         memset(disk_super->metadata_uuid, 0, BTRFS_FSID_SIZE);
  151     } else if (new_uuid && uuid_changed && memcmp(disk_super->metadata_uuid,
  152                         new_fsid, BTRFS_FSID_SIZE)) {
  153         /*
  154          * Changing fsid on an already changed FS, in this case we
  155          * only change the fsid and don't touch metadata uuid as it
  156          * has already the correct value
  157          */
  158         memcpy(disk_super->fsid, &new_fsid, BTRFS_FSID_SIZE);
  159     } else if (new_uuid && !uuid_changed) {
  160         /*
  161          * First time changing the fsid, copy the fsid to metadata_uuid
  162          */
  163         incompat_flags |= BTRFS_FEATURE_INCOMPAT_METADATA_UUID;
  164         btrfs_set_super_incompat_flags(disk_super, incompat_flags);
  165         memcpy(disk_super->metadata_uuid, disk_super->fsid,
  166                BTRFS_FSID_SIZE);
  167         memcpy(disk_super->fsid, &new_fsid, BTRFS_FSID_SIZE);
  168     } else {
  169         /* Setting the same fsid as current, do nothing */
  170         return 0;
  171     }
  172 
  173     trans = btrfs_start_transaction(root, 1);
  174 
  175     /*
  176      * Step 2 is to write the metadata_uuid, set the incompat flag and
  177      * clear the in progress flag
  178      */
  179     super_flags &= ~BTRFS_SUPER_FLAG_CHANGING_FSID_V2;
  180     btrfs_set_super_flags(disk_super, super_flags);
  181 
  182     /* Then actually copy the metadata uuid and set the incompat bit */
  183 
  184     return btrfs_commit_transaction(trans, root);
  185 }
  186 
  187 static int set_super_incompat_flags(struct btrfs_root *root, u64 flags)
  188 {
  189     struct btrfs_trans_handle *trans;
  190     struct btrfs_super_block *disk_super;
  191     u64 super_flags;
  192     int ret;
  193 
  194     disk_super = root->fs_info->super_copy;
  195     super_flags = btrfs_super_incompat_flags(disk_super);
  196     super_flags |= flags;
  197     trans = btrfs_start_transaction(root, 1);
  198     BUG_ON(IS_ERR(trans));
  199     btrfs_set_super_incompat_flags(disk_super, super_flags);
  200     ret = btrfs_commit_transaction(trans, root);
  201 
  202     return ret;
  203 }
  204 
  205 static int change_buffer_header_uuid(struct extent_buffer *eb, uuid_t new_fsid)
  206 {
  207     struct btrfs_fs_info *fs_info = eb->fs_info;
  208     int same_fsid = 1;
  209     int same_chunk_tree_uuid = 1;
  210     int ret;
  211 
  212     same_fsid = !memcmp_extent_buffer(eb, new_fsid, btrfs_header_fsid(),
  213                       BTRFS_FSID_SIZE);
  214     same_chunk_tree_uuid =
  215         !memcmp_extent_buffer(eb, fs_info->new_chunk_tree_uuid,
  216                 btrfs_header_chunk_tree_uuid(eb),
  217                 BTRFS_UUID_SIZE);
  218     if (same_fsid && same_chunk_tree_uuid)
  219         return 0;
  220     if (!same_fsid)
  221         write_extent_buffer(eb, new_fsid, btrfs_header_fsid(),
  222                     BTRFS_FSID_SIZE);
  223     if (!same_chunk_tree_uuid)
  224         write_extent_buffer(eb, fs_info->new_chunk_tree_uuid,
  225                     btrfs_header_chunk_tree_uuid(eb),
  226                     BTRFS_UUID_SIZE);
  227     ret = write_tree_block(NULL, fs_info, eb);
  228 
  229     return ret;
  230 }
  231 
  232 static int change_extents_uuid(struct btrfs_fs_info *fs_info, uuid_t new_fsid)
  233 {
  234     struct btrfs_root *root = fs_info->extent_root;
  235     struct btrfs_path path;
  236     struct btrfs_key key = {0, 0, 0};
  237     int ret = 0;
  238 
  239     btrfs_init_path(&path);
  240     /*
  241      * Here we don't use transaction as it will takes a lot of reserve
  242      * space, and that will make a near-full btrfs unable to change uuid
  243      */
  244     ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
  245     if (ret < 0)
  246         goto out;
  247 
  248     while (1) {
  249         struct btrfs_extent_item *ei;
  250         struct extent_buffer *eb;
  251         u64 flags;
  252         u64 bytenr;
  253 
  254         btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
  255         if (key.type != BTRFS_EXTENT_ITEM_KEY &&
  256             key.type != BTRFS_METADATA_ITEM_KEY)
  257             goto next;
  258         ei = btrfs_item_ptr(path.nodes[0], path.slots[0],
  259                     struct btrfs_extent_item);
  260         flags = btrfs_extent_flags(path.nodes[0], ei);
  261         if (!(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK))
  262             goto next;
  263 
  264         bytenr = key.objectid;
  265         eb = read_tree_block(fs_info, bytenr, 0);
  266         if (IS_ERR(eb)) {
  267             error("failed to read tree block: %llu", bytenr);
  268             ret = PTR_ERR(eb);
  269             goto out;
  270         }
  271         ret = change_buffer_header_uuid(eb, new_fsid);
  272         free_extent_buffer(eb);
  273         if (ret < 0) {
  274             error("failed to change uuid of tree block: %llu",
  275                 bytenr);
  276             goto out;
  277         }
  278 next:
  279         ret = btrfs_next_item(root, &path);
  280         if (ret < 0)
  281             goto out;
  282         if (ret > 0) {
  283             ret = 0;
  284             goto out;
  285         }
  286     }
  287 
  288 out:
  289     btrfs_release_path(&path);
  290     return ret;
  291 }
  292 
  293 static int change_device_uuid(struct extent_buffer *eb, int slot,
  294                   uuid_t new_fsid)
  295 {
  296     struct btrfs_dev_item *di;
  297     struct btrfs_fs_info *fs_info = eb->fs_info;
  298     int ret = 0;
  299 
  300     di = btrfs_item_ptr(eb, slot, struct btrfs_dev_item);
  301     if (!memcmp_extent_buffer(eb, new_fsid,
  302                   (unsigned long)btrfs_device_fsid(di),
  303                   BTRFS_FSID_SIZE))
  304         return ret;
  305 
  306     write_extent_buffer(eb, new_fsid, (unsigned long)btrfs_device_fsid(di),
  307                 BTRFS_FSID_SIZE);
  308     ret = write_tree_block(NULL, fs_info, eb);
  309 
  310     return ret;
  311 }
  312 
  313 static int change_devices_uuid(struct btrfs_root *root, uuid_t new_fsid)
  314 {
  315     struct btrfs_path path;
  316     struct btrfs_key key = {0, 0, 0};
  317     int ret = 0;
  318 
  319     btrfs_init_path(&path);
  320     /* No transaction again */
  321     ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
  322     if (ret < 0)
  323         goto out;
  324 
  325     while (1) {
  326         btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
  327         if (key.type != BTRFS_DEV_ITEM_KEY ||
  328             key.objectid != BTRFS_DEV_ITEMS_OBJECTID)
  329             goto next;
  330         ret = change_device_uuid(path.nodes[0], path.slots[0],
  331                      new_fsid);
  332         if (ret < 0)
  333             goto out;
  334 next:
  335         ret = btrfs_next_item(root, &path);
  336         if (ret < 0)
  337             goto out;
  338         if (ret > 0) {
  339             ret = 0;
  340             goto out;
  341         }
  342     }
  343 out:
  344     btrfs_release_path(&path);
  345     return ret;
  346 }
  347 
  348 static int change_fsid_prepare(struct btrfs_fs_info *fs_info, uuid_t new_fsid)
  349 {
  350     struct btrfs_root *tree_root = fs_info->tree_root;
  351     u64 flags = btrfs_super_flags(fs_info->super_copy);
  352     int ret = 0;
  353 
  354     flags |= BTRFS_SUPER_FLAG_CHANGING_FSID;
  355     btrfs_set_super_flags(fs_info->super_copy, flags);
  356 
  357     memcpy(fs_info->super_copy->fsid, new_fsid, BTRFS_FSID_SIZE);
  358     ret = write_all_supers(fs_info);
  359     if (ret < 0)
  360         return ret;
  361 
  362     /* Also need to change the metadatauuid of the fs info */
  363     memcpy(fs_info->fs_devices->metadata_uuid, new_fsid, BTRFS_FSID_SIZE);
  364 
  365     /* also restore new chunk_tree_id into tree_root for restore */
  366     write_extent_buffer(tree_root->node, fs_info->new_chunk_tree_uuid,
  367                 btrfs_header_chunk_tree_uuid(tree_root->node),
  368                 BTRFS_UUID_SIZE);
  369     return write_tree_block(NULL, fs_info, tree_root->node);
  370 }
  371 
  372 static int change_fsid_done(struct btrfs_fs_info *fs_info)
  373 {
  374     u64 flags = btrfs_super_flags(fs_info->super_copy);
  375 
  376     flags &= ~BTRFS_SUPER_FLAG_CHANGING_FSID;
  377     btrfs_set_super_flags(fs_info->super_copy, flags);
  378 
  379     return write_all_supers(fs_info);
  380 }
  381 
  382 
  383 /*
  384  * Change fsid of a given fs.
  385  *
  386  * If new_fsid_str is not given, use a random generated UUID.
  387  * Caller should check new_fsid_str is valid
  388  */
  389 static int change_uuid(struct btrfs_fs_info *fs_info, const char *new_fsid_str)
  390 {
  391     uuid_t new_fsid;
  392     uuid_t new_chunk_id;
  393     uuid_t old_fsid;
  394     char uuid_buf[BTRFS_UUID_UNPARSED_SIZE];
  395     int ret = 0;
  396 
  397     if (check_unfinished_fsid_change(fs_info, new_fsid, new_chunk_id)) {
  398         if (new_fsid_str) {
  399             uuid_t tmp;
  400 
  401             uuid_parse(new_fsid_str, tmp);
  402             if (memcmp(tmp, new_fsid, BTRFS_FSID_SIZE)) {
  403                 error(
  404         "new fsid %s is not the same with unfinished fsid change",
  405                     new_fsid_str);
  406                 return -EINVAL;
  407             }
  408         }
  409     } else {
  410         if (new_fsid_str)
  411             uuid_parse(new_fsid_str, new_fsid);
  412         else
  413             uuid_generate(new_fsid);
  414 
  415         uuid_generate(new_chunk_id);
  416     }
  417     fs_info->new_chunk_tree_uuid = new_chunk_id;
  418 
  419     memcpy(old_fsid, (const char*)fs_info->fs_devices->fsid, BTRFS_UUID_SIZE);
  420     uuid_unparse(old_fsid, uuid_buf);
  421     printf("Current fsid: %s\n", uuid_buf);
  422 
  423     uuid_unparse(new_fsid, uuid_buf);
  424     printf("New fsid: %s\n", uuid_buf);
  425     /* Now we can begin fsid change */
  426     printf("Set superblock flag CHANGING_FSID\n");
  427     ret = change_fsid_prepare(fs_info, new_fsid);
  428     if (ret < 0)
  429         goto out;
  430 
  431     /* Change extents first */
  432     printf("Change fsid in extents\n");
  433     ret = change_extents_uuid(fs_info, new_fsid);
  434     if (ret < 0) {
  435         error("failed to change UUID of metadata: %d", ret);
  436         goto out;
  437     }
  438 
  439     /* Then devices */
  440     printf("Change fsid on devices\n");
  441     ret = change_devices_uuid(fs_info->chunk_root, new_fsid);
  442     if (ret < 0) {
  443         error("failed to change UUID of devices: %d", ret);
  444         goto out;
  445     }
  446 
  447     /* Last, change fsid in super */
  448     memcpy(fs_info->fs_devices->fsid, new_fsid, BTRFS_FSID_SIZE);
  449     memcpy(fs_info->super_copy->fsid, new_fsid, BTRFS_FSID_SIZE);
  450     ret = write_all_supers(fs_info);
  451     if (ret < 0)
  452         goto out;
  453 
  454     /* Now fsid change is done */
  455     printf("Clear superblock flag CHANGING_FSID\n");
  456     ret = change_fsid_done(fs_info);
  457     fs_info->new_chunk_tree_uuid = NULL;
  458     printf("Fsid change finished\n");
  459 out:
  460     return ret;
  461 }
  462 
  463 static void print_usage(void)
  464 {
  465     printf("usage: btrfstune [options] device\n");
  466     printf("Tune settings of filesystem features on an unmounted device\n\n");
  467     printf("Options:\n");
  468     printf("  change feature status:\n");
  469     printf("\t-r          enable extended inode refs (mkfs: extref, for hardlink limits)\n");
  470     printf("\t-x          enable skinny metadata extent refs (mkfs: skinny-metadata)\n");
  471     printf("\t-n          enable no-holes feature (mkfs: no-holes, more efficient sparse file representation)\n");
  472     printf("\t-S <0|1>    set/unset seeding status of a device\n");
  473     printf("  uuid changes:\n");
  474     printf("\t-u          rewrite fsid, use a random one\n");
  475     printf("\t-U UUID     rewrite fsid to UUID\n");
  476     printf("\t-m          change fsid in metadata_uuid to a random UUID\n");
  477     printf("\t            (incompat change, more lightweight than -u|-U)\n");
  478     printf("\t-M UUID     change fsid in metadata_uuid to UUID\n");
  479     printf("  general:\n");
  480     printf("\t-f          allow dangerous operations, make sure that you are aware of the dangers\n");
  481     printf("\t--help      print this help\n");
  482 }
  483 
  484 int BOX_MAIN(btrfstune)(int argc, char *argv[])
  485 {
  486     struct btrfs_root *root;
  487     unsigned ctree_flags = OPEN_CTREE_WRITES;
  488     int success = 0;
  489     int total = 0;
  490     int seeding_flag = 0;
  491     u64 seeding_value = 0;
  492     int random_fsid = 0;
  493     int change_metadata_uuid = 0;
  494     char *new_fsid_str = NULL;
  495     int ret;
  496     u64 super_flags = 0;
  497     int fd = -1;
  498 
  499     while(1) {
  500         static const struct option long_options[] = {
  501             { "help", no_argument, NULL, GETOPT_VAL_HELP},
  502             { NULL, 0, NULL, 0 }
  503         };
  504         int c = getopt_long(argc, argv, "S:rxfuU:nmM:", long_options, NULL);
  505 
  506         if (c < 0)
  507             break;
  508         switch(c) {
  509         case 'S':
  510             seeding_flag = 1;
  511             seeding_value = arg_strtou64(optarg);
  512             break;
  513         case 'r':
  514             super_flags |= BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF;
  515             break;
  516         case 'x':
  517             super_flags |= BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA;
  518             break;
  519         case 'n':
  520             super_flags |= BTRFS_FEATURE_INCOMPAT_NO_HOLES;
  521             break;
  522         case 'f':
  523             force = 1;
  524             break;
  525         case 'U':
  526             ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
  527             new_fsid_str = optarg;
  528             break;
  529         case 'u':
  530             ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
  531             random_fsid = 1;
  532             break;
  533         case 'M':
  534             ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
  535             change_metadata_uuid = 1;
  536             new_fsid_str = optarg;
  537             break;
  538         case 'm':
  539             ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
  540             change_metadata_uuid = 1;
  541             break;
  542         case GETOPT_VAL_HELP:
  543         default:
  544             print_usage();
  545             return c != GETOPT_VAL_HELP;
  546         }
  547     }
  548 
  549     set_argv0(argv);
  550     device = argv[optind];
  551     if (check_argc_exact(argc - optind, 1))
  552         return 1;
  553 
  554     if (random_fsid && new_fsid_str) {
  555         error("random fsid can't be used with specified fsid");
  556         return 1;
  557     }
  558     if (!super_flags && !seeding_flag && !(random_fsid || new_fsid_str) &&
  559         !change_metadata_uuid) {
  560         error("at least one option should be specified");
  561         print_usage();
  562         return 1;
  563     }
  564 
  565     if (new_fsid_str) {
  566         uuid_t tmp;
  567 
  568         ret = uuid_parse(new_fsid_str, tmp);
  569         if (ret < 0) {
  570             error("could not parse UUID: %s", new_fsid_str);
  571             return 1;
  572         }
  573         if (!test_uuid_unique(new_fsid_str)) {
  574             error("fsid %s is not unique", new_fsid_str);
  575             return 1;
  576         }
  577     }
  578 
  579     fd = open(device, O_RDWR);
  580     if (fd < 0) {
  581         error("mount check: cannot open %s: %m", device);
  582         return 1;
  583     }
  584 
  585     ret = check_mounted_where(fd, device, NULL, 0, NULL,
  586             SBREAD_IGNORE_FSID_MISMATCH);
  587     if (ret < 0) {
  588         errno = -ret;
  589         error("could not check mount status of %s: %m", device);
  590         close(fd);
  591         return 1;
  592     } else if (ret) {
  593         error("%s is mounted", device);
  594         close(fd);
  595         return 1;
  596     }
  597 
  598     root = open_ctree_fd(fd, device, 0, ctree_flags);
  599 
  600     if (!root) {
  601         error("open ctree failed");
  602         return 1;
  603     }
  604 
  605     if (seeding_flag) {
  606         if (btrfs_fs_incompat(root->fs_info, METADATA_UUID)) {
  607             fprintf(stderr, "SEED flag cannot be changed on a metadata-uuid changed fs\n");
  608             ret = 1;
  609             goto out;
  610         }
  611 
  612         if (!seeding_value && !force) {
  613             warning(
  614 "this is dangerous, clearing the seeding flag may cause the derived device not to be mountable!");
  615             ret = ask_user("We are going to clear the seeding flag, are you sure?");
  616             if (!ret) {
  617                 fprintf(stderr, "Clear seeding flag canceled\n");
  618                 ret = 1;
  619                 goto out;
  620             }
  621         }
  622 
  623         ret = update_seeding_flag(root, seeding_value);
  624         if (!ret)
  625             success++;
  626         total++;
  627     }
  628 
  629     if (super_flags) {
  630         ret = set_super_incompat_flags(root, super_flags);
  631         if (!ret)
  632             success++;
  633         total++;
  634     }
  635 
  636     if (change_metadata_uuid) {
  637         if (seeding_flag) {
  638             fprintf(stderr,
  639         "Not allowed to set both seeding flag and uuid metadata\n");
  640             ret = 1;
  641             goto out;
  642         }
  643 
  644         if (new_fsid_str)
  645             ret = set_metadata_uuid(root, new_fsid_str);
  646         else
  647             ret = set_metadata_uuid(root, NULL);
  648 
  649         if (!ret)
  650             success++;
  651         total++;
  652     }
  653 
  654     if (random_fsid || (new_fsid_str && !change_metadata_uuid)) {
  655         if (btrfs_fs_incompat(root->fs_info, METADATA_UUID)) {
  656             fprintf(stderr,
  657         "Cannot rewrite fsid while METADATA_UUID flag is active. \n"
  658         "Ensure fsid and metadata_uuid match before retrying.\n");
  659             ret = 1;
  660             goto out;
  661         }
  662 
  663         if (!force) {
  664             warning(
  665 "it's recommended to run 'btrfs check --readonly' before this operation.\n"
  666 "\tThe whole operation must finish before the filesystem can be mounted again.\n"
  667 "\tIf cancelled or interrupted, run 'btrfstune -u' to restart.");
  668             ret = ask_user("We are going to change UUID, are your sure?");
  669             if (!ret) {
  670                 fprintf(stderr, "UUID change canceled\n");
  671                 ret = 1;
  672                 goto out;
  673             }
  674         }
  675         ret = change_uuid(root->fs_info, new_fsid_str);
  676         if (!ret)
  677             success++;
  678         total++;
  679     }
  680 
  681     if (success == total) {
  682         ret = 0;
  683     } else {
  684         root->fs_info->readonly = 1;
  685         ret = 1;
  686         error("btrfstune failed");
  687     }
  688 out:
  689     close_ctree(root);
  690     btrfs_close_all_devices();
  691 
  692     return ret;
  693 }