diff --git a/cmds-check.c b/cmds-check.c index 44b19d8d..9fd53f42 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -4060,7 +4060,7 @@ int cmd_check(int argc, char **argv) return -EBUSY; } - info = open_ctree_fs_info(argv[optind], bytenr, rw, 1); + info = open_ctree_fs_info(argv[optind], bytenr, 0, rw, 1); if (!info) { fprintf(stderr, "Couldn't open file system\n"); return -EIO; diff --git a/cmds-restore.c b/cmds-restore.c index c75e1872..fc31f0cf 100644 --- a/cmds-restore.c +++ b/cmds-restore.c @@ -833,27 +833,64 @@ static int do_list_roots(struct btrfs_root *root) static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_mirror, int list_roots) { + struct btrfs_fs_info *fs_info = NULL; struct btrfs_root *root = NULL; u64 bytenr; int i; for (i = super_mirror; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); - root = open_ctree_recovery(dev, bytenr, root_location); - if (root) + fs_info = open_ctree_fs_info(dev, bytenr, root_location, 0, 1); + if (fs_info) break; fprintf(stderr, "Could not open root, trying backup super\n"); } - if (root && list_roots) { - int ret = do_list_roots(root); - if (ret) { + if (!fs_info) + return NULL; + + /* + * All we really need to succeed is reading the chunk tree, everything + * else we can do by hand, since we only need to read the tree root and + * the fs_root. + */ + if (!extent_buffer_uptodate(fs_info->tree_root->node)) { + u64 generation; + + root = fs_info->tree_root; + if (!root_location) + root_location = btrfs_super_root(fs_info->super_copy); + generation = btrfs_super_generation(fs_info->super_copy); + root->node = read_tree_block(root, root_location, + root->leafsize, generation); + if (!extent_buffer_uptodate(root->node)) { + fprintf(stderr, "Error opening tree root\n"); close_ctree(root); - root = NULL; + return NULL; } } - return root; + if (!list_roots && !fs_info->fs_root) { + struct btrfs_key key; + + key.objectid = BTRFS_FS_TREE_OBJECTID; + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = (u64)-1; + fs_info->fs_root = btrfs_read_fs_root_no_cache(fs_info, &key); + if (IS_ERR(fs_info->fs_root)) { + fprintf(stderr, "Couldn't read fs root: %ld\n", + PTR_ERR(fs_info->fs_root)); + close_ctree(fs_info->tree_root); + return NULL; + } + } + + if (list_roots && do_list_roots(fs_info->tree_root)) { + close_ctree(fs_info->tree_root); + return NULL; + } + + return fs_info->fs_root; } static int find_first_dir(struct btrfs_root *root, u64 *objectid) diff --git a/debug-tree.c b/debug-tree.c index 0fc0ecdf..bae7f945 100644 --- a/debug-tree.c +++ b/debug-tree.c @@ -166,7 +166,7 @@ int main(int ac, char **av) if (ac != 1) print_usage(); - info = open_ctree_fs_info(av[optind], 0, 0, 1); + info = open_ctree_fs_info(av[optind], 0, 0, 0, 1); if (!info) { fprintf(stderr, "unable to open %s\n", av[optind]); exit(1); diff --git a/disk-io.c b/disk-io.c index be4abb8b..b001e35a 100644 --- a/disk-io.c +++ b/disk-io.c @@ -945,8 +945,10 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, if (!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_METADUMP)) { ret = btrfs_read_chunk_tree(chunk_root); - if (ret) - goto out_failed; + if (ret) { + printk("Couldn't read chunk tree\n"); + goto out_chunk; + } } blocksize = btrfs_level_size(tree_root, @@ -1019,6 +1021,7 @@ out_failed: free_extent_buffer(fs_info->extent_root->node); if (fs_info->tree_root) free_extent_buffer(fs_info->tree_root->node); +out_chunk: if (fs_info->chunk_root) free_extent_buffer(fs_info->chunk_root->node); out_devices: @@ -1041,8 +1044,8 @@ out: } struct btrfs_fs_info *open_ctree_fs_info(const char *filename, - u64 sb_bytenr, int writes, - int partial) + u64 sb_bytenr, u64 root_tree_bytenr, + int writes, int partial) { int fp; struct btrfs_fs_info *info; @@ -1056,7 +1059,8 @@ struct btrfs_fs_info *open_ctree_fs_info(const char *filename, fprintf (stderr, "Could not open %s\n", filename); return NULL; } - info = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes, partial); + info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, + writes, partial); close(fp); return info; } @@ -1065,28 +1069,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, writes, 0); - if (!info) - return NULL; - return info->fs_root; -} - -struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr, - u64 root_tree_bytenr) -{ - int fp; - struct btrfs_fs_info *info; - - - fp = open(filename, O_RDONLY); - if (fp < 0) { - fprintf (stderr, "Could not open %s\n", filename); - return NULL; - } - info = __open_ctree_fd(fp, filename, sb_bytenr, - root_tree_bytenr, 0, 0); - close(fp); - + info = open_ctree_fs_info(filename, sb_bytenr, 0, writes, 0); if (!info) return NULL; return info->fs_root; diff --git a/disk-io.h b/disk-io.h index ff879581..c29ee8e2 100644 --- a/disk-io.h +++ b/disk-io.h @@ -50,11 +50,9 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes); struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, int writes); -struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr, - u64 root_tree_bytenr); struct btrfs_fs_info *open_ctree_fs_info(const char *filename, - u64 sb_bytenr, int writes, - int partial); + u64 sb_bytenr, u64 root_tree_bytenr, + int writes, int partial); int close_ctree(struct btrfs_root *root); int write_all_supers(struct btrfs_root *root); int write_ctree_super(struct btrfs_trans_handle *trans,