summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds-check.c2
-rw-r--r--cmds-restore.c51
-rw-r--r--debug-tree.c2
-rw-r--r--disk-io.c37
-rw-r--r--disk-io.h6
5 files changed, 58 insertions, 40 deletions
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,