summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2013-03-12 13:38:16 -0400
committerDavid Sterba <dsterba@suse.cz>2013-03-18 18:14:19 +0100
commit7854c8b667654502f69e05584729146a06827bc6 (patch)
treecbcb98fc6d4994f974a7f950587b09f1d3830fea
parentb268a417259b9db69d3f845c8510acbbac10e2d9 (diff)
Btrfs-progs: give restore a list roots option
Since restore has the ability to open really really screwed up file systems, add a list roots option to it so we can still get the contents of the tree root on a horribly broken fs. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com>
-rw-r--r--cmds-restore.c92
1 files changed, 85 insertions, 7 deletions
diff --git a/cmds-restore.c b/cmds-restore.c
index e71a28f0..c75e1872 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -770,9 +770,70 @@ next:
return 0;
}
-static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_mirror)
+static int do_list_roots(struct btrfs_root *root)
{
- struct btrfs_root *root;
+ struct btrfs_key key;
+ struct btrfs_key found_key;
+ struct btrfs_disk_key disk_key;
+ struct btrfs_path *path;
+ struct extent_buffer *leaf;
+ struct btrfs_root_item ri;
+ unsigned long offset;
+ int slot;
+ int ret;
+
+ root = root->fs_info->tree_root;
+ path = btrfs_alloc_path();
+ if (!path) {
+ fprintf(stderr, "Failed to alloc path\n");
+ return -1;
+ }
+
+ key.offset = 0;
+ key.objectid = 0;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to do search %d\n", ret);
+ btrfs_free_path(path);
+ return -1;
+ }
+
+ while (1) {
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ if (slot >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret)
+ break;
+ leaf = path->nodes[0];
+ slot = path->slots[0];
+ }
+ btrfs_item_key(leaf, &disk_key, slot);
+ btrfs_disk_key_to_cpu(&found_key, &disk_key);
+ if (btrfs_key_type(&found_key) != BTRFS_ROOT_ITEM_KEY) {
+ path->slots[0]++;
+ continue;
+ }
+
+ offset = btrfs_item_ptr_offset(leaf, slot);
+ read_extent_buffer(leaf, &ri, offset, sizeof(ri));
+ printf(" tree ");
+ btrfs_print_key(&disk_key);
+ printf(" %Lu level %d\n", btrfs_root_bytenr(&ri),
+ btrfs_root_level(&ri));
+ path->slots[0]++;
+ }
+ btrfs_free_path(path);
+
+ return 0;
+}
+
+static struct btrfs_root *open_fs(const char *dev, u64 root_location,
+ int super_mirror, int list_roots)
+{
+ struct btrfs_root *root = NULL;
u64 bytenr;
int i;
@@ -780,11 +841,19 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_
bytenr = btrfs_sb_offset(i);
root = open_ctree_recovery(dev, bytenr, root_location);
if (root)
- return root;
+ break;
fprintf(stderr, "Could not open root, trying backup super\n");
}
- return NULL;
+ if (root && list_roots) {
+ int ret = do_list_roots(root);
+ if (ret) {
+ close_ctree(root);
+ root = NULL;
+ }
+ }
+
+ return root;
}
static int find_first_dir(struct btrfs_root *root, u64 *objectid)
@@ -875,8 +944,9 @@ int cmd_restore(int argc, char **argv)
int opt;
int super_mirror = 0;
int find_dir = 0;
+ int list_roots = 0;
- while ((opt = getopt(argc, argv, "sviot:u:df:r:")) != -1) {
+ while ((opt = getopt(argc, argv, "sviot:u:df:r:l")) != -1) {
switch (opt) {
case 's':
get_snaps = 1;
@@ -927,12 +997,17 @@ int cmd_restore(int argc, char **argv)
exit(1);
}
break;
+ case 'l':
+ list_roots = 1;
+ break;
default:
usage(cmd_restore_usage);
}
}
- if (optind + 1 >= argc)
+ if (!list_roots && optind + 1 >= argc)
+ usage(cmd_restore_usage);
+ else if (list_roots && optind >= argc)
usage(cmd_restore_usage);
if ((ret = check_mounted(argv[optind])) < 0) {
@@ -944,10 +1019,13 @@ int cmd_restore(int argc, char **argv)
return 1;
}
- root = open_fs(argv[optind], tree_location, super_mirror);
+ root = open_fs(argv[optind], tree_location, super_mirror, list_roots);
if (root == NULL)
return 1;
+ if (list_roots)
+ goto out;
+
if (fs_location != 0) {
free_extent_buffer(root->node);
root->node = read_tree_block(root, fs_location, 4096, 0);