diff options
-rw-r--r-- | btrfs-image.c | 163 | ||||
-rw-r--r-- | man/btrfs-image.8.in | 5 |
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, |