From fb0cfed5d3500e76ce30c6a9803ee1720bf1b4a5 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 7 Dec 2011 14:13:35 -0500 Subject: [PATCH 31/35] Btrfs-progs: fix restore to fall back to the broken open_ctree We don't need most of the roots when doing restore, like the extent tree. So if the recovery open_ctree fails because it's trying to open one of these useless roots just fall back to open_ctree_broken. This will just open the chunk root which is the bare minimum of what we need to operate. Then from there we can setup the tree_root and the fs_root, and if either of those are gone we can't restore anyway. Thanks, Signed-off-by: Josef Bacik --- disk-io.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++ disk-io.h | 1 + find-root.c | 166 ----------------------------------------------------------- restore.c | 48 +++++++++++++++++- 4 files changed, 198 insertions(+), 167 deletions(-) diff --git a/disk-io.c b/disk-io.c index 9585057..8a8071c 100644 --- a/disk-io.c +++ b/disk-io.c @@ -883,6 +883,156 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, return __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev); } +struct btrfs_root *open_ctree_broken(int fd, const char *device) +{ + u32 sectorsize; + u32 nodesize; + u32 leafsize; + u32 blocksize; + u32 stripesize; + u64 generation; + struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root)); + struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); + struct btrfs_root *chunk_root = malloc(sizeof(struct btrfs_root)); + struct btrfs_root *dev_root = malloc(sizeof(struct btrfs_root)); + struct btrfs_root *csum_root = malloc(sizeof(struct btrfs_root)); + struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info)); + int ret; + struct btrfs_super_block *disk_super; + struct btrfs_fs_devices *fs_devices = NULL; + u64 total_devs; + u64 features; + + ret = btrfs_scan_one_device(fd, device, &fs_devices, + &total_devs, BTRFS_SUPER_INFO_OFFSET); + + if (ret) { + fprintf(stderr, "No valid Btrfs found on %s\n", device); + goto out; + } + + if (total_devs != 1) { + ret = btrfs_scan_for_fsid(fs_devices, total_devs, 1); + if (ret) + goto out; + } + + memset(fs_info, 0, sizeof(*fs_info)); + fs_info->tree_root = tree_root; + fs_info->extent_root = extent_root; + fs_info->chunk_root = chunk_root; + fs_info->dev_root = dev_root; + fs_info->csum_root = csum_root; + + fs_info->readonly = 1; + + extent_io_tree_init(&fs_info->extent_cache); + extent_io_tree_init(&fs_info->free_space_cache); + extent_io_tree_init(&fs_info->block_group_cache); + extent_io_tree_init(&fs_info->pinned_extents); + extent_io_tree_init(&fs_info->pending_del); + extent_io_tree_init(&fs_info->extent_ins); + cache_tree_init(&fs_info->fs_root_cache); + + cache_tree_init(&fs_info->mapping_tree.cache_tree); + + mutex_init(&fs_info->fs_mutex); + fs_info->fs_devices = fs_devices; + INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); + INIT_LIST_HEAD(&fs_info->space_info); + + __setup_root(4096, 4096, 4096, 4096, tree_root, + fs_info, BTRFS_ROOT_TREE_OBJECTID); + + ret = btrfs_open_devices(fs_devices, O_RDONLY); + if (ret) + goto out_cleanup; + + fs_info->super_bytenr = BTRFS_SUPER_INFO_OFFSET; + disk_super = &fs_info->super_copy; + ret = btrfs_read_dev_super(fs_devices->latest_bdev, + disk_super, BTRFS_SUPER_INFO_OFFSET); + if (ret) { + printk("No valid btrfs found\n"); + goto out_devices; + } + + memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE); + + + features = btrfs_super_incompat_flags(disk_super) & + ~BTRFS_FEATURE_INCOMPAT_SUPP; + if (features) { + printk("couldn't open because of unsupported " + "option features (%Lx).\n", features); + goto out_devices; + } + + features = btrfs_super_incompat_flags(disk_super); + if (!(features & BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF)) { + features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF; + btrfs_set_super_incompat_flags(disk_super, features); + } + + nodesize = btrfs_super_nodesize(disk_super); + leafsize = btrfs_super_leafsize(disk_super); + sectorsize = btrfs_super_sectorsize(disk_super); + stripesize = btrfs_super_stripesize(disk_super); + tree_root->nodesize = nodesize; + tree_root->leafsize = leafsize; + tree_root->sectorsize = sectorsize; + tree_root->stripesize = stripesize; + + ret = btrfs_read_sys_array(tree_root); + if (ret) + goto out_devices; + blocksize = btrfs_level_size(tree_root, + btrfs_super_chunk_root_level(disk_super)); + generation = btrfs_super_chunk_root_generation(disk_super); + + __setup_root(nodesize, leafsize, sectorsize, stripesize, + chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID); + + chunk_root->node = read_tree_block(chunk_root, + btrfs_super_chunk_root(disk_super), + blocksize, generation); + if (!chunk_root->node) { + printk("Couldn't read chunk root\n"); + goto out_devices; + } + + read_extent_buffer(chunk_root->node, fs_info->chunk_tree_uuid, + (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node), + BTRFS_UUID_SIZE); + + if (!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_METADUMP)) { + ret = btrfs_read_chunk_tree(chunk_root); + if (ret) + goto out_chunk; + } + + return fs_info->chunk_root; +out_chunk: + free_extent_buffer(fs_info->chunk_root->node); +out_devices: + close_all_devices(fs_info); +out_cleanup: + extent_io_tree_cleanup(&fs_info->extent_cache); + extent_io_tree_cleanup(&fs_info->free_space_cache); + extent_io_tree_cleanup(&fs_info->block_group_cache); + extent_io_tree_cleanup(&fs_info->pinned_extents); + extent_io_tree_cleanup(&fs_info->pending_del); + extent_io_tree_cleanup(&fs_info->extent_ins); +out: + free(tree_root); + free(extent_root); + free(chunk_root); + free(dev_root); + free(csum_root); + free(fs_info); + return NULL; +} + int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr) { u8 fsid[BTRFS_FSID_SIZE]; diff --git a/disk-io.h b/disk-io.h index 8fdcd91..2b1fcd5 100644 --- a/disk-io.h +++ b/disk-io.h @@ -48,6 +48,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, int writes, int use_earliest_bdev); struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr, u64 root_tree_bytenr); +struct btrfs_root *open_ctree_broken(int fd, const char *device); int close_ctree(struct btrfs_root *root); int write_all_supers(struct btrfs_root *root); int write_ctree_super(struct btrfs_trans_handle *trans, diff --git a/find-root.c b/find-root.c index bd44e1f..e0bc069 100644 --- a/find-root.c +++ b/find-root.c @@ -92,172 +92,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, return 0; } -static int close_all_devices(struct btrfs_fs_info *fs_info) -{ - struct list_head *list; - struct list_head *next; - struct btrfs_device *device; - - return 0; - - list = &fs_info->fs_devices->devices; - list_for_each(next, list) { - device = list_entry(next, struct btrfs_device, dev_list); - close(device->fd); - } - return 0; -} - -static struct btrfs_root *open_ctree_broken(int fd, const char *device) -{ - u32 sectorsize; - u32 nodesize; - u32 leafsize; - u32 blocksize; - u32 stripesize; - u64 generation; - struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root)); - struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); - struct btrfs_root *chunk_root = malloc(sizeof(struct btrfs_root)); - struct btrfs_root *dev_root = malloc(sizeof(struct btrfs_root)); - struct btrfs_root *csum_root = malloc(sizeof(struct btrfs_root)); - struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info)); - int ret; - struct btrfs_super_block *disk_super; - struct btrfs_fs_devices *fs_devices = NULL; - u64 total_devs; - u64 features; - - ret = btrfs_scan_one_device(fd, device, &fs_devices, - &total_devs, BTRFS_SUPER_INFO_OFFSET); - - if (ret) { - fprintf(stderr, "No valid Btrfs found on %s\n", device); - goto out; - } - - if (total_devs != 1) { - ret = btrfs_scan_for_fsid(fs_devices, total_devs, 1); - if (ret) - goto out; - } - - memset(fs_info, 0, sizeof(*fs_info)); - fs_info->tree_root = tree_root; - fs_info->extent_root = extent_root; - fs_info->chunk_root = chunk_root; - fs_info->dev_root = dev_root; - fs_info->csum_root = csum_root; - - fs_info->readonly = 1; - - extent_io_tree_init(&fs_info->extent_cache); - extent_io_tree_init(&fs_info->free_space_cache); - extent_io_tree_init(&fs_info->block_group_cache); - extent_io_tree_init(&fs_info->pinned_extents); - extent_io_tree_init(&fs_info->pending_del); - extent_io_tree_init(&fs_info->extent_ins); - cache_tree_init(&fs_info->fs_root_cache); - - cache_tree_init(&fs_info->mapping_tree.cache_tree); - - mutex_init(&fs_info->fs_mutex); - fs_info->fs_devices = fs_devices; - INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); - INIT_LIST_HEAD(&fs_info->space_info); - - __setup_root(4096, 4096, 4096, 4096, tree_root, - fs_info, BTRFS_ROOT_TREE_OBJECTID); - - ret = btrfs_open_devices(fs_devices, O_RDONLY); - if (ret) - goto out_cleanup; - - fs_info->super_bytenr = BTRFS_SUPER_INFO_OFFSET; - disk_super = &fs_info->super_copy; - ret = btrfs_read_dev_super(fs_devices->latest_bdev, - disk_super, BTRFS_SUPER_INFO_OFFSET); - if (ret) { - printk("No valid btrfs found\n"); - goto out_devices; - } - - memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE); - - - features = btrfs_super_incompat_flags(disk_super) & - ~BTRFS_FEATURE_INCOMPAT_SUPP; - if (features) { - printk("couldn't open because of unsupported " - "option features (%Lx).\n", features); - goto out_devices; - } - - features = btrfs_super_incompat_flags(disk_super); - if (!(features & BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF)) { - features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF; - btrfs_set_super_incompat_flags(disk_super, features); - } - - nodesize = btrfs_super_nodesize(disk_super); - leafsize = btrfs_super_leafsize(disk_super); - sectorsize = btrfs_super_sectorsize(disk_super); - stripesize = btrfs_super_stripesize(disk_super); - tree_root->nodesize = nodesize; - tree_root->leafsize = leafsize; - tree_root->sectorsize = sectorsize; - tree_root->stripesize = stripesize; - - ret = btrfs_read_sys_array(tree_root); - if (ret) - goto out_devices; - blocksize = btrfs_level_size(tree_root, - btrfs_super_chunk_root_level(disk_super)); - generation = btrfs_super_chunk_root_generation(disk_super); - - __setup_root(nodesize, leafsize, sectorsize, stripesize, - chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID); - - chunk_root->node = read_tree_block(chunk_root, - btrfs_super_chunk_root(disk_super), - blocksize, generation); - if (!chunk_root->node) { - printk("Couldn't read chunk root\n"); - goto out_devices; - } - - read_extent_buffer(chunk_root->node, fs_info->chunk_tree_uuid, - (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node), - BTRFS_UUID_SIZE); - - if (!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_METADUMP)) { - ret = btrfs_read_chunk_tree(chunk_root); - if (ret) - goto out_chunk; - } - - return fs_info->chunk_root; -out_chunk: - free_extent_buffer(fs_info->chunk_root->node); -out_devices: - close_all_devices(fs_info); -out_cleanup: - extent_io_tree_cleanup(&fs_info->extent_cache); - extent_io_tree_cleanup(&fs_info->free_space_cache); - extent_io_tree_cleanup(&fs_info->block_group_cache); - extent_io_tree_cleanup(&fs_info->pinned_extents); - extent_io_tree_cleanup(&fs_info->pending_del); - extent_io_tree_cleanup(&fs_info->extent_ins); -out: - free(tree_root); - free(extent_root); - free(chunk_root); - free(dev_root); - free(csum_root); - free(fs_info); - return NULL; -} - static int dump_root_bytenr(struct btrfs_root *root, u64 bytenr, u64 gen) { struct btrfs_root *tmp = malloc(sizeof(struct btrfs_root)); diff --git a/restore.c b/restore.c index a4ccb18..90d54e4 100644 --- a/restore.c +++ b/restore.c @@ -779,9 +779,13 @@ static void usage() static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_mirror) { + struct btrfs_key key; struct btrfs_root *root; u64 bytenr; + u64 generation; + u32 blocksize; int i; + int dev_fd; for (i = super_mirror; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); @@ -791,7 +795,49 @@ static struct btrfs_root *open_fs(const char *dev, u64 root_location, int super_ fprintf(stderr, "Could not open root, trying backup super\n"); } - return NULL; + fprintf(stderr, "Ok couldn't open the root the normal way, trying " + "the broken way\n"); + + dev_fd = open(dev, O_RDONLY); + if (dev_fd < 0) { + fprintf(stderr, "Failed to open device %s\n", dev); + return NULL; + } + + root = open_ctree_broken(dev_fd, dev); + close(dev_fd); + if (!root) { + fprintf(stderr, "Broken ctree open failed\n"); + return NULL; + } + if (!root_location) + bytenr = btrfs_super_root(&root->fs_info->super_copy); + + blocksize = btrfs_level_size(root, + btrfs_super_root_level(&root->fs_info->super_copy)); + generation = btrfs_super_generation(&root->fs_info->super_copy); + + root->fs_info->tree_root->node = read_tree_block(root, bytenr, + blocksize, + generation); + if (!root->fs_info->tree_root->node) { + fprintf(stderr, "Couldn't read tree node\n"); + close_ctree(root); + return NULL; + } + + key.objectid = BTRFS_FS_TREE_OBJECTID; + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = (u64)-1; + + root->fs_info->fs_root = btrfs_read_fs_root(root->fs_info, &key); + if (!root->fs_info->fs_root) { + fprintf(stderr, "Couldn't read fs_root\n"); + close_ctree(root); + return NULL; + } + + return root->fs_info->fs_root; } static int find_first_dir(struct btrfs_root *root, u64 *objectid) -- 1.7.6.233.gd79bc