summaryrefslogtreecommitdiff
path: root/cmds-restore.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-04-16 13:13:38 -0400
committerDavid Sterba <dsterba@suse.cz>2013-04-23 18:56:27 +0200
commitaa5f0626f8a7797278e55e9976c2e868962af8da (patch)
tree9c6107453dfc48f69352d39e3ff7113415454004 /cmds-restore.c
parent18ce0501ce8a6bc2d66b6bf11358d284919c5d3c (diff)
Btrfs-progs: make restore deal with really broken file systems
All we need for restore to work is the chunk root, the tree root and the fs root we want to restore from. So to do this we need to make a few adjustments 1) Make open_ctree_fs_info fail completely if it can't read the chunk tree. There is no sense in continuing if we can't read the chunk tree since we won't be able to translate logical to physical blocks. 2) Use open_ctree_fs_info in restore, and if we didn't load a tree root or fs root go ahead and try to set those up manually ourselves. This is related to work I did last year on restore, but it uses the open_ctree_fs_info instead of my open coded open_ctree. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'cmds-restore.c')
-rw-r--r--cmds-restore.c51
1 files changed, 44 insertions, 7 deletions
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)