btrfs-progs: Add new option for specify chunk root bytenr
[platform/upstream/btrfs-progs.git] / cmds-check.c
index 266451a..0a48535 100644 (file)
@@ -35,6 +35,7 @@
 #include "utils.h"
 #include "commands.h"
 #include "free-space-cache.h"
+#include "free-space-tree.h"
 #include "btrfsck.h"
 #include "qgroup-verify.h"
 #include "rbtree-utils.h"
@@ -4586,6 +4587,8 @@ static int add_extent_rec(struct cache_tree *extent_cache,
                return ret;
        }
        rec = malloc(sizeof(*rec));
+       if (!rec)
+               return -ENOMEM;
        rec->start = start;
        rec->max_size = max_size;
        rec->nr = max(nr, max_size);
@@ -5474,9 +5477,29 @@ static int check_space_cache(struct btrfs_root *root)
                        btrfs_remove_free_space_cache(cache);
                }
 
-               ret = load_free_space_cache(root->fs_info, cache);
-               if (!ret)
-                       continue;
+               if (btrfs_fs_compat_ro(root->fs_info,
+                                      BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE)) {
+                       ret = exclude_super_stripes(root, cache);
+                       if (ret) {
+                               fprintf(stderr, "could not exclude super stripes: %s\n",
+                                       strerror(-ret));
+                               error++;
+                               continue;
+                       }
+                       ret = load_free_space_tree(root->fs_info, cache);
+                       free_excluded_extents(root, cache);
+                       if (ret < 0) {
+                               fprintf(stderr, "could not load free space tree: %s\n",
+                                       strerror(-ret));
+                               error++;
+                               continue;
+                       }
+                       error += ret;
+               } else {
+                       ret = load_free_space_cache(root->fs_info, cache);
+                       if (!ret)
+                               continue;
+               }
 
                ret = verify_space_cache(root, cache);
                if (ret) {
@@ -9195,11 +9218,11 @@ static int build_roots_info_cache(struct btrfs_fs_info *info)
                        iref = (struct btrfs_extent_inline_ref *)(ei + 1);
                        level = found_key.offset;
                } else {
-                       struct btrfs_tree_block_info *info;
+                       struct btrfs_tree_block_info *binfo;
 
-                       info = (struct btrfs_tree_block_info *)(ei + 1);
-                       iref = (struct btrfs_extent_inline_ref *)(info + 1);
-                       level = btrfs_tree_block_level(leaf, info);
+                       binfo = (struct btrfs_tree_block_info *)(ei + 1);
+                       iref = (struct btrfs_extent_inline_ref *)(binfo + 1);
+                       level = btrfs_tree_block_level(leaf, binfo);
                }
 
                /*
@@ -9457,6 +9480,7 @@ const char * const cmd_check_usage[] = {
        "-E|--subvol-extents <subvolid>",
        "                            print subvolume extents and sharing state",
        "-r|--tree-root <bytenr>     use the given bytenr for the tree root",
+       "-c|--chunk-root <bytenr>    use the given bytenr for the chunk tree root",
        "-p|--progress               indicate progress",
        NULL
 };
@@ -9469,6 +9493,7 @@ int cmd_check(int argc, char **argv)
        u64 bytenr = 0;
        u64 subvolid = 0;
        u64 tree_root_bytenr = 0;
+       u64 chunk_root_bytenr = 0;
        char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
        int ret;
        u64 num;
@@ -9492,11 +9517,12 @@ int cmd_check(int argc, char **argv)
                        { "subvol-extents", required_argument, NULL, 'E' },
                        { "qgroup-report", no_argument, NULL, 'Q' },
                        { "tree-root", required_argument, NULL, 'r' },
+                       { "chunk-root", required_argument, NULL, 'c' },
                        { "progress", no_argument, NULL, 'p' },
                        { NULL, 0, NULL, 0}
                };
 
-               c = getopt_long(argc, argv, "as:br:p", long_options, NULL);
+               c = getopt_long(argc, argv, "as:br:pc:", long_options, NULL);
                if (c < 0)
                        break;
                switch(c) {
@@ -9525,6 +9551,9 @@ int cmd_check(int argc, char **argv)
                        case 'r':
                                tree_root_bytenr = arg_strtou64(optarg);
                                break;
+                       case 'c':
+                               chunk_root_bytenr = arg_strtou64(optarg);
+                               break;
                        case 'p':
                                ctx.progress_enabled = true;
                                break;
@@ -9556,9 +9585,8 @@ int cmd_check(int argc, char **argv)
                                break;
                }
        }
-       argc = argc - optind;
 
-       if (check_argc_exact(argc, 1))
+       if (check_argc_exact(argc - optind, 1))
                usage(cmd_check_usage);
 
        if (ctx.progress_enabled) {
@@ -9589,7 +9617,7 @@ int cmd_check(int argc, char **argv)
                ctree_flags |= OPEN_CTREE_PARTIAL;
 
        info = open_ctree_fs_info(argv[optind], bytenr, tree_root_bytenr,
-                                 ctree_flags);
+                                 chunk_root_bytenr, ctree_flags);
        if (!info) {
                fprintf(stderr, "Couldn't open file system\n");
                ret = -EIO;
@@ -9715,8 +9743,12 @@ int cmd_check(int argc, char **argv)
                goto close_out;
        }
 
-       if (!ctx.progress_enabled)
-               fprintf(stderr, "checking free space cache\n");
+       if (!ctx.progress_enabled) {
+               if (btrfs_fs_compat_ro(info, BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE))
+                       fprintf(stderr, "checking free space tree\n");
+               else
+                       fprintf(stderr, "checking free space cache\n");
+       }
        ret = check_space_cache(root);
        if (ret)
                goto out;