btrfsprogs/0130-Btrfs-progs-fix-restore-to-fall-back-to-the-broken-o.patch

444 lines
13 KiB
Diff

From fb0cfed5d3500e76ce30c6a9803ee1720bf1b4a5 Mon Sep 17 00:00:00 2001
From: Josef Bacik <josef@redhat.com>
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 <josef@redhat.com>
---
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