Btrfs-progs: add -b to btrfsck to look at backup roots
authorJosef Bacik <jbacik@fusionio.com>
Wed, 23 Oct 2013 20:24:03 +0000 (16:24 -0400)
committerChris Mason <chris.mason@fusionio.com>
Thu, 7 Nov 2013 18:29:30 +0000 (13:29 -0500)
In some cases the tree root is so hosed we can't get anything useful out of it.
So add the -b option to btrfsck to make us look for the most recent backup tree
root to use for repair.  Then we can hopefully get ourselves into a working
state.  Thanks,

Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
btrfs-debug-tree.c
cmds-check.c
cmds-restore.c
disk-io.c
disk-io.h

index 078dac5..4a9d89d 100644 (file)
@@ -171,7 +171,7 @@ int main(int ac, char **av)
        if (ac != 1)
                print_usage();
 
-       info = open_ctree_fs_info(av[optind], 0, 0, 0, 1);
+       info = open_ctree_fs_info(av[optind], 0, 0, 0, 1, 0);
        if (!info) {
                fprintf(stderr, "unable to open %s\n", av[optind]);
                exit(1);
index 668af15..3453cac 100644 (file)
@@ -6022,6 +6022,7 @@ static struct option long_options[] = {
        { "repair", 0, NULL, 0 },
        { "init-csum-tree", 0, NULL, 0 },
        { "init-extent-tree", 0, NULL, 0 },
+       { "backup", 0, NULL, 0 },
        { NULL, 0, NULL, 0}
 };
 
@@ -6030,6 +6031,7 @@ const char * const cmd_check_usage[] = {
        "Check an unmounted btrfs filesystem.",
        "",
        "-s|--super <superblock>     use this superblock copy",
+       "-b|--backup                 use the backup root copy",
        "--repair                    try to repair the filesystem",
        "--init-csum-tree            create a new CRC tree",
        "--init-extent-tree          create a new extent tree",
@@ -6043,6 +6045,7 @@ int cmd_check(int argc, char **argv)
        struct btrfs_fs_info *info;
        u64 bytenr = 0;
        char uuidbuf[37];
+       int backup_root = 0;
        int ret;
        int num;
        int option_index = 0;
@@ -6052,12 +6055,15 @@ int cmd_check(int argc, char **argv)
 
        while(1) {
                int c;
-               c = getopt_long(argc, argv, "as:", long_options,
+               c = getopt_long(argc, argv, "as:b", long_options,
                                &option_index);
                if (c < 0)
                        break;
                switch(c) {
                        case 'a': /* ignored */ break;
+                       case 'b':
+                               backup_root = 1;
+                               break;
                        case 's':
                                num = atol(optarg);
                                bytenr = btrfs_sb_offset(num);
@@ -6099,7 +6105,7 @@ int cmd_check(int argc, char **argv)
                return -EBUSY;
        }
 
-       info = open_ctree_fs_info(argv[optind], bytenr, 0, rw, 1);
+       info = open_ctree_fs_info(argv[optind], bytenr, 0, rw, 1, backup_root);
        if (!info) {
                fprintf(stderr, "Couldn't open file system\n");
                return -EIO;
index ae0527b..e315d2e 100644 (file)
@@ -974,7 +974,7 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location,
 
        for (i = super_mirror; i < BTRFS_SUPER_MIRROR_MAX; i++) {
                bytenr = btrfs_sb_offset(i);
-               fs_info = open_ctree_fs_info(dev, bytenr, root_location, 0, 1);
+               fs_info = open_ctree_fs_info(dev, bytenr, root_location, 0, 1, 0);
                if (fs_info)
                        break;
                fprintf(stderr, "Could not open root, trying backup super\n");
index ca76c42..733714d 100644 (file)
--- a/disk-io.c
+++ b/disk-io.c
@@ -808,8 +808,27 @@ int btrfs_check_fs_compatibility(struct btrfs_super_block *sb, int writable)
        return 0;
 }
 
+static int find_best_backup_root(struct btrfs_super_block *super)
+{
+       struct btrfs_root_backup *backup;
+       u64 orig_gen = btrfs_super_generation(super);
+       u64 gen = 0;
+       int best_index = 0;
+       int i;
+
+       for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) {
+               backup = super->super_roots + i;
+               if (btrfs_backup_tree_root_gen(backup) != orig_gen &&
+                   btrfs_backup_tree_root_gen(backup) > gen) {
+                       best_index = i;
+                       gen = btrfs_backup_tree_root_gen(backup);
+               }
+       }
+       return best_index;
+}
+
 int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info,
-                         u64 root_tree_bytenr, int partial)
+                         u64 root_tree_bytenr, int partial, int backup_root)
 {
        struct btrfs_super_block *sb = fs_info->super_copy;
        struct btrfs_root *root;
@@ -833,8 +852,20 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info,
        blocksize = btrfs_level_size(root, btrfs_super_root_level(sb));
        generation = btrfs_super_generation(sb);
 
-       if (!root_tree_bytenr)
+       if (!root_tree_bytenr && !backup_root) {
                root_tree_bytenr = btrfs_super_root(sb);
+       } else if (backup_root) {
+               struct btrfs_root_backup *backup;
+               int index = find_best_backup_root(sb);
+               if (index >= BTRFS_NUM_BACKUP_ROOTS) {
+                       fprintf(stderr, "Invalid backup root number\n");
+                       return -EIO;
+               }
+               backup = fs_info->super_copy->super_roots + index;
+               root_tree_bytenr = btrfs_backup_tree_root(backup);
+               generation = btrfs_backup_tree_root_gen(backup);
+       }
+
        root->node = read_tree_block(root, root_tree_bytenr, blocksize,
                                     generation);
        if (!extent_buffer_uptodate(root->node)) {
@@ -1005,7 +1036,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
                                             u64 sb_bytenr,
                                             u64 root_tree_bytenr, int writes,
                                             int partial, int restore,
-                                            int recover_super)
+                                            int recover_super,
+                                            int backup_root)
 {
        struct btrfs_fs_info *fs_info;
        struct btrfs_super_block *disk_super;
@@ -1068,7 +1100,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
                           (unsigned long)btrfs_header_chunk_tree_uuid(eb),
                           BTRFS_UUID_SIZE);
 
-       ret = btrfs_setup_all_roots(fs_info, root_tree_bytenr, partial);
+       ret = btrfs_setup_all_roots(fs_info, root_tree_bytenr, partial,
+                                   backup_root);
        if (ret)
                goto out_failed;
 
@@ -1105,14 +1138,15 @@ struct btrfs_fs_info *open_ctree_fs_info_restore(const char *filename,
                return NULL;
        }
        info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr,
-                              writes, partial, restore, 0);
+                              writes, partial, restore, 0, 0);
        close(fp);
        return info;
 }
 
 struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
                                         u64 sb_bytenr, u64 root_tree_bytenr,
-                                        int writes, int partial)
+                                        int writes, int partial,
+                                        int backup_root)
 {
        int fp;
        struct btrfs_fs_info *info;
@@ -1127,7 +1161,7 @@ struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
                return NULL;
        }
        info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr,
-                              writes, partial, 0, 0);
+                              writes, partial, 0, 0, backup_root);
        close(fp);
        return info;
 }
@@ -1148,7 +1182,7 @@ struct btrfs_root *open_ctree_with_broken_super(const char *filename,
                return NULL;
        }
        info = __open_ctree_fd(fp, filename, sb_bytenr, 0,
-                              writes, 0, 0, 1);
+                              writes, 0, 0, 1, 0);
        close(fp);
        if (info)
                return info->fs_root;
@@ -1159,7 +1193,7 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
 {
        struct btrfs_fs_info *info;
 
-       info = open_ctree_fs_info(filename, sb_bytenr, 0, writes, 0);
+       info = open_ctree_fs_info(filename, sb_bytenr, 0, writes, 0, 0);
        if (!info)
                return NULL;
        return info->fs_root;
@@ -1169,7 +1203,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
                                 int writes)
 {
        struct btrfs_fs_info *info;
-       info = __open_ctree_fd(fp, path, sb_bytenr, 0, writes, 0, 0, 0);
+       info = __open_ctree_fd(fp, path, sb_bytenr, 0, writes, 0, 0, 0, 0);
        if (!info)
                return NULL;
        return info->fs_root;
index 6f2d4f4..b0292db 100644 (file)
--- a/disk-io.h
+++ b/disk-io.h
@@ -53,7 +53,7 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info);
 struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr);
 int btrfs_check_fs_compatibility(struct btrfs_super_block *sb, int writable);
 int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info,
-                         u64 root_tree_bytenr, int partial);
+                         u64 root_tree_bytenr, int partial, int backup_root);
 void btrfs_release_all_roots(struct btrfs_fs_info *fs_info);
 void btrfs_cleanup_all_caches(struct btrfs_fs_info *fs_info);
 int btrfs_scan_fs_devices(int fd, const char *path,
@@ -69,7 +69,8 @@ struct btrfs_fs_info *open_ctree_fs_info_restore(const char *filename,
                                         int writes, int partial);
 struct btrfs_fs_info *open_ctree_fs_info(const char *filename,
                                         u64 sb_bytenr, u64 root_tree_bytenr,
-                                        int writes, int partial);
+                                        int writes, int partial,
+                                        int backup_root);
 struct btrfs_root *open_ctree_with_broken_super(const char *filename,
                                        u64 sb_bytenr, int writes);
 int close_ctree(struct btrfs_root *root);