summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--btrfs-image.c163
-rw-r--r--man/btrfs-image.8.in5
2 files changed, 103 insertions, 65 deletions
diff --git a/btrfs-image.c b/btrfs-image.c
index 9a0a2493..188291ca 100644
--- a/btrfs-image.c
+++ b/btrfs-image.c
@@ -605,9 +605,8 @@ static int is_tree_block(struct btrfs_root *extent_root,
}
#endif
-static int copy_log_blocks(struct btrfs_root *root, struct extent_buffer *eb,
- struct metadump_struct *metadump,
- int log_root_tree)
+static int copy_tree_blocks(struct btrfs_root *root, struct extent_buffer *eb,
+ struct metadump_struct *metadump, int root_tree)
{
struct extent_buffer *tmp;
struct btrfs_root_item *ri;
@@ -624,7 +623,7 @@ static int copy_log_blocks(struct btrfs_root *root, struct extent_buffer *eb,
return ret;
}
- if (btrfs_header_level(eb) == 0 && !log_root_tree)
+ if (btrfs_header_level(eb) == 0 && !root_tree)
return 0;
level = btrfs_header_level(eb);
@@ -642,7 +641,7 @@ static int copy_log_blocks(struct btrfs_root *root, struct extent_buffer *eb,
"Error reading log root block\n");
return -EIO;
}
- ret = copy_log_blocks(root, tmp, metadump, 0);
+ ret = copy_tree_blocks(root, tmp, metadump, 0);
free_extent_buffer(tmp);
if (ret)
return ret;
@@ -653,8 +652,7 @@ static int copy_log_blocks(struct btrfs_root *root, struct extent_buffer *eb,
fprintf(stderr, "Error reading log block\n");
return -EIO;
}
- ret = copy_log_blocks(root, tmp, metadump,
- log_root_tree);
+ ret = copy_tree_blocks(root, tmp, metadump, root_tree);
free_extent_buffer(tmp);
if (ret)
return ret;
@@ -679,8 +677,8 @@ static int copy_log_trees(struct btrfs_root *root,
return -EIO;
}
- return copy_log_blocks(root, root->fs_info->log_root_tree->node,
- metadump, 1);
+ return copy_tree_blocks(root, root->fs_info->log_root_tree->node,
+ metadump, 1);
}
static int copy_space_cache(struct btrfs_root *root,
@@ -749,51 +747,18 @@ static int copy_space_cache(struct btrfs_root *root,
return 0;
}
-static int create_metadump(const char *input, FILE *out, int num_threads,
- int compress_level)
+static int copy_from_extent_tree(struct metadump_struct *metadump,
+ struct btrfs_path *path)
{
- struct btrfs_root *root;
struct btrfs_root *extent_root;
- struct btrfs_path *path = NULL;
struct extent_buffer *leaf;
struct btrfs_extent_item *ei;
struct btrfs_key key;
- struct metadump_struct metadump;
u64 bytenr;
u64 num_bytes;
int ret;
- int err = 0;
-
- root = open_ctree(input, 0, 0);
- if (!root) {
- fprintf(stderr, "Open ctree failed\n");
- return -EIO;
- }
-
- BUG_ON(root->nodesize != root->leafsize);
-
- ret = metadump_init(&metadump, root, out, num_threads,
- compress_level);
- if (ret) {
- fprintf(stderr, "Error initing metadump %d\n", ret);
- close_ctree(root);
- return ret;
- }
-
- ret = add_extent(BTRFS_SUPER_INFO_OFFSET, 4096, &metadump, 0);
- if (ret) {
- fprintf(stderr, "Error adding metadata %d\n", ret);
- err = ret;
- goto out;
- }
- extent_root = root->fs_info->extent_root;
- path = btrfs_alloc_path();
- if (!path) {
- fprintf(stderr, "Out of memory allocing path\n");
- err = -ENOMEM;
- goto out;
- }
+ extent_root = metadump->root->fs_info->extent_root;
bytenr = BTRFS_SUPER_INFO_OFFSET + 4096;
key.objectid = bytenr;
key.type = BTRFS_EXTENT_ITEM_KEY;
@@ -802,9 +767,9 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
if (ret < 0) {
fprintf(stderr, "Error searching extent root %d\n", ret);
- err = ret;
- goto out;
+ return ret;
}
+ ret = 0;
while (1) {
leaf = path->nodes[0];
@@ -813,11 +778,12 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
if (ret < 0) {
fprintf(stderr, "Error going to next leaf %d"
"\n", ret);
- err = ret;
- goto out;
+ break;
}
- if (ret > 0)
+ if (ret > 0) {
+ ret = 0;
break;
+ }
leaf = path->nodes[0];
}
@@ -833,20 +799,19 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
if (key.type == BTRFS_METADATA_ITEM_KEY)
num_bytes = key.offset;
else
- num_bytes = root->leafsize;
+ num_bytes = extent_root->leafsize;
if (btrfs_item_size_nr(leaf, path->slots[0]) > sizeof(*ei)) {
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_extent_item);
if (btrfs_extent_flags(leaf, ei) &
BTRFS_EXTENT_FLAG_TREE_BLOCK) {
- ret = add_extent(bytenr, num_bytes, &metadump,
+ ret = add_extent(bytenr, num_bytes, metadump,
0);
if (ret) {
fprintf(stderr, "Error adding block "
"%d\n", ret);
- err = ret;
- goto out;
+ break;
}
}
} else {
@@ -855,31 +820,94 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
if (ret < 0) {
fprintf(stderr, "Error checking tree block "
"%d\n", ret);
- err = ret;
- goto out;
+ break;
}
if (ret) {
- ret = add_extent(bytenr, num_bytes, &metadump,
+ ret = add_extent(bytenr, num_bytes, metadump,
0);
if (ret) {
fprintf(stderr, "Error adding block "
"%d\n", ret);
- err = ret;
- goto out;
+ break;
}
}
+ ret = 0;
#else
fprintf(stderr, "Either extent tree corruption or "
"you haven't built with V0 support\n");
- err = -EIO;
- goto out;
+ ret = -EIO;
+ break;
#endif
}
bytenr += num_bytes;
}
- btrfs_release_path(root, path);
+ btrfs_release_path(extent_root, path);
+
+ return ret;
+}
+
+static int create_metadump(const char *input, FILE *out, int num_threads,
+ int compress_level, int walk_trees)
+{
+ struct btrfs_root *root;
+ struct btrfs_path *path = NULL;
+ struct metadump_struct metadump;
+ int ret;
+ int err = 0;
+
+ root = open_ctree(input, 0, 0);
+ if (!root) {
+ fprintf(stderr, "Open ctree failed\n");
+ return -EIO;
+ }
+
+ BUG_ON(root->nodesize != root->leafsize);
+
+ ret = metadump_init(&metadump, root, out, num_threads,
+ compress_level);
+ if (ret) {
+ fprintf(stderr, "Error initing metadump %d\n", ret);
+ close_ctree(root);
+ return ret;
+ }
+
+ ret = add_extent(BTRFS_SUPER_INFO_OFFSET, 4096, &metadump, 0);
+ if (ret) {
+ fprintf(stderr, "Error adding metadata %d\n", ret);
+ err = ret;
+ goto out;
+ }
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ fprintf(stderr, "Out of memory allocing path\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ if (walk_trees) {
+ ret = copy_tree_blocks(root, root->fs_info->chunk_root->node,
+ &metadump, 1);
+ if (ret) {
+ err = ret;
+ goto out;
+ }
+
+ ret = copy_tree_blocks(root, root->fs_info->tree_root->node,
+ &metadump, 1);
+ if (ret) {
+ err = ret;
+ goto out;
+ }
+ } else {
+ ret = copy_from_extent_tree(&metadump, path);
+ if (ret) {
+ err = ret;
+ goto out;
+ }
+ }
ret = copy_log_trees(root, &metadump, path);
if (ret) {
@@ -892,7 +920,7 @@ out:
ret = flush_pending(&metadump, 1);
if (ret) {
if (!err)
- ret = err;
+ err = ret;
fprintf(stderr, "Error flushing pending %d\n", ret);
}
@@ -1498,6 +1526,7 @@ static void print_usage(void)
fprintf(stderr, "\t-c value\tcompression level (0 ~ 9)\n");
fprintf(stderr, "\t-t value\tnumber of threads (1 ~ 32)\n");
fprintf(stderr, "\t-o \tdon't mess with the chunk tree when restoring\n");
+ fprintf(stderr, "\t-w \twalk all trees instead of using extent tree, do this if your extent tree is broken\n");
exit(1);
}
@@ -1509,11 +1538,12 @@ int main(int argc, char *argv[])
int compress_level = 0;
int create = 1;
int old_restore = 0;
+ int walk_trees = 0;
int ret;
FILE *out;
while (1) {
- int c = getopt(argc, argv, "rc:t:o");
+ int c = getopt(argc, argv, "rc:t:ow");
if (c < 0)
break;
switch (c) {
@@ -1533,6 +1563,9 @@ int main(int argc, char *argv[])
case 'o':
old_restore = 1;
break;
+ case 'w':
+ walk_trees = 1;
+ break;
default:
print_usage();
}
@@ -1565,7 +1598,7 @@ int main(int argc, char *argv[])
if (create)
ret = create_metadump(source, out, num_threads,
- compress_level);
+ compress_level, walk_trees);
else
ret = restore_metadump(source, out, old_restore, 1);
diff --git a/man/btrfs-image.8.in b/man/btrfs-image.8.in
index b738f672..7e0e3b0b 100644
--- a/man/btrfs-image.8.in
+++ b/man/btrfs-image.8.in
@@ -28,6 +28,11 @@ number of threads (1 ~ 32) to be used to process the image dump or restore.
\fB\-o\fP
use the old restore method, this does not fixup the chunk tree so the restored
file system will not be able to be mounted.
+.TP
+\fB\-w\fP
+Walk all the trees manually and copy any blocks that are referenced. Use this
+option if your extent tree is corrupted to make sure that all of the metadata is
+captured.
.SH AVAILABILITY
.B btrfs-image
is part of btrfs-progs. Btrfs is currently under heavy development,