444 lines
13 KiB
Diff
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
|
||
|
|