From e7580bb29644128d19cfe70a16df713bdcc58a43 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sun, 5 Feb 2012 16:11:48 -0500 Subject: [PATCH] Add open_ctree_fs_info for partial FS opens fsck needs to be able to open a damaged FS, which means open_ctree needs to be able to return a damaged FS. This adds a new open_ctree_fs_info which can be used to open any and all roots that are valid. btrfs-debug-tree is changed to use it. Signed-off-by: Chris Mason --- btrfsck.c | 7 ++-- debug-tree.c | 59 ++++++++++++++++++++++----------- disk-io.c | 94 ++++++++++++++++++++++++++++++++++------------------ disk-io.h | 3 ++ extent_io.c | 3 ++ 5 files changed, 112 insertions(+), 54 deletions(-) diff --git a/btrfsck.c b/btrfsck.c index 3a23e665..a56bb4bf 100644 --- a/btrfsck.c +++ b/btrfsck.c @@ -2809,6 +2809,7 @@ int main(int ac, char **av) { struct cache_tree root_cache; struct btrfs_root *root; + struct btrfs_fs_info *info; u64 bytenr = 0; int ret; int num; @@ -2845,11 +2846,13 @@ int main(int ac, char **av) return -EBUSY; } - root = open_ctree(av[optind], bytenr, 0); + info = open_ctree_fs_info(av[optind], bytenr, 0, 0); - if (root == NULL) + if (info == NULL) return 1; + root = info->fs_root; + ret = check_extents(root); if (ret) goto out; diff --git a/debug-tree.c b/debug-tree.c index 2aeabfd7..c497892e 100644 --- a/debug-tree.c +++ b/debug-tree.c @@ -104,6 +104,7 @@ static void print_old_roots(struct btrfs_super_block *super) int main(int ac, char **av) { struct btrfs_root *root; + struct btrfs_fs_info *info; struct btrfs_path path; struct btrfs_key key; struct btrfs_root_item ri; @@ -152,12 +153,18 @@ int main(int ac, char **av) if (ac != 1) print_usage(); - root = open_ctree(av[optind], 0, 0); - if (!root) { + info = open_ctree_fs_info(av[optind], 0, 0, 1); + if (!info) { fprintf(stderr, "unable to open %s\n", av[optind]); exit(1); } + root = info->fs_root; + if (block_only) { + if (!root) { + fprintf(stderr, "unable to open %s\n", av[optind]); + exit(1); + } leaf = read_tree_block(root, block_only, root->leafsize, 0); @@ -184,25 +191,32 @@ int main(int ac, char **av) if (!extent_only) { if (roots_only) { printf("root tree: %llu level %d\n", - (unsigned long long)root->fs_info->tree_root->node->start, - btrfs_header_level(root->fs_info->tree_root->node)); + (unsigned long long)info->tree_root->node->start, + btrfs_header_level(info->tree_root->node)); printf("chunk tree: %llu level %d\n", - (unsigned long long)root->fs_info->chunk_root->node->start, - btrfs_header_level(root->fs_info->chunk_root->node)); + (unsigned long long)info->chunk_root->node->start, + btrfs_header_level(info->chunk_root->node)); } else { - printf("root tree\n"); - btrfs_print_tree(root->fs_info->tree_root, - root->fs_info->tree_root->node, 1); + if (info->tree_root->node) { + printf("root tree\n"); + btrfs_print_tree(info->tree_root, + info->tree_root->node, 1); + } - printf("chunk tree\n"); - btrfs_print_tree(root->fs_info->chunk_root, - root->fs_info->chunk_root->node, 1); + if (info->chunk_root->node) { + printf("chunk tree\n"); + btrfs_print_tree(info->chunk_root, + info->chunk_root->node, 1); + } } } - tree_root_scan = root->fs_info->tree_root; + tree_root_scan = info->tree_root; btrfs_init_path(&path); again: + if (!extent_buffer_uptodate(tree_root_scan->node)) + goto no_node; + key.offset = 0; key.objectid = 0; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); @@ -232,6 +246,9 @@ again: btrfs_level_size(tree_root_scan, btrfs_root_level(&ri)), 0); + if (!extent_buffer_uptodate(buf)) + goto next; + switch(found_key.objectid) { case BTRFS_ROOT_TREE_OBJECTID: if (!skip) @@ -320,13 +337,15 @@ again: } } } +next: path.slots[0]++; } +no_node: btrfs_release_path(root, &path); - if (tree_root_scan == root->fs_info->tree_root && - root->fs_info->log_root_tree) { - tree_root_scan = root->fs_info->log_root_tree; + if (tree_root_scan == info->tree_root && + info->log_root_tree) { + tree_root_scan = info->log_root_tree; goto again; } @@ -334,14 +353,14 @@ again: return 0; if (root_backups) - print_old_roots(&root->fs_info->super_copy); + print_old_roots(&info->super_copy); printf("total bytes %llu\n", - (unsigned long long)btrfs_super_total_bytes(&root->fs_info->super_copy)); + (unsigned long long)btrfs_super_total_bytes(&info->super_copy)); printf("bytes used %llu\n", - (unsigned long long)btrfs_super_bytes_used(&root->fs_info->super_copy)); + (unsigned long long)btrfs_super_bytes_used(&info->super_copy)); uuidbuf[36] = '\0'; - uuid_unparse(root->fs_info->super_copy.fsid, uuidbuf); + uuid_unparse(info->super_copy.fsid, uuidbuf); printf("uuid %s\n", uuidbuf); printf("%s\n", BTRFS_BUILD_VERSION); return 0; diff --git a/disk-io.c b/disk-io.c index 408b2d58..58aec02b 100644 --- a/disk-io.c +++ b/disk-io.c @@ -444,7 +444,9 @@ static int find_and_setup_root(struct btrfs_root *tree_root, generation = btrfs_root_generation(&root->root_item); root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), blocksize, generation); - BUG_ON(!root->node); + if (!extent_buffer_uptodate(root->node)) + return -EIO; + return 0; } @@ -471,7 +473,9 @@ static int find_and_setup_log_root(struct btrfs_root *tree_root, btrfs_super_generation(disk_super) + 1); fs_info->log_root_tree = log_root; - BUG_ON(!log_root->node); + + if (!extent_buffer_uptodate(log_root->node)) + return -EIO; return 0; } @@ -580,7 +584,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, return fs_info->dev_root; if (location->objectid == BTRFS_CSUM_TREE_OBJECTID) return fs_info->csum_root; - + BUG_ON(location->objectid == BTRFS_TREE_RELOC_OBJECTID || location->offset != (u64)-1); @@ -601,8 +605,10 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, return root; } -struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, - u64 root_tree_bytenr, int writes) +static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, + u64 sb_bytenr, + u64 root_tree_bytenr, int writes, + int partial) { u32 sectorsize; u32 nodesize; @@ -733,7 +739,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, chunk_root->node = read_tree_block(chunk_root, btrfs_super_chunk_root(disk_super), blocksize, generation); - if (!chunk_root->node) { + if (!extent_buffer_uptodate(chunk_root->node)) { printk("Couldn't read chunk root\n"); goto out_devices; } @@ -745,7 +751,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, if (!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_METADUMP)) { ret = btrfs_read_chunk_tree(chunk_root); if (ret) - goto out_chunk; + goto out_failed; } blocksize = btrfs_level_size(tree_root, @@ -757,15 +763,15 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, tree_root->node = read_tree_block(tree_root, root_tree_bytenr, blocksize, generation); - if (!tree_root->node) { + if (!extent_buffer_uptodate(tree_root->node)) { printk("Couldn't read tree root\n"); - goto out_chunk; + goto out_failed; } ret = find_and_setup_root(tree_root, fs_info, BTRFS_EXTENT_TREE_OBJECTID, extent_root); if (ret) { printk("Couldn't setup extent tree\n"); - goto out_tree; + goto out_failed; } extent_root->track_dirty = 1; @@ -773,7 +779,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, BTRFS_DEV_TREE_OBJECTID, dev_root); if (ret) { printk("Couldn't setup device tree\n"); - goto out_extent; + goto out_failed; } dev_root->track_dirty = 1; @@ -781,7 +787,7 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, BTRFS_CSUM_TREE_OBJECTID, csum_root); if (ret) { printk("Couldn't setup csum tree\n"); - goto out_dev; + goto out_failed; } csum_root->track_dirty = 1; @@ -797,23 +803,28 @@ struct btrfs_root *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, fs_info->fs_root = btrfs_read_fs_root(fs_info, &key); if (!fs_info->fs_root) - goto out_csum; + goto out_failed; fs_info->data_alloc_profile = (u64)-1; fs_info->metadata_alloc_profile = (u64)-1; fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; - return fs_info->fs_root; -out_csum: - free_extent_buffer(fs_info->csum_root->node); -out_dev: - free_extent_buffer(fs_info->dev_root->node); -out_extent: - free_extent_buffer(fs_info->extent_root->node); -out_tree: - free_extent_buffer(fs_info->tree_root->node); -out_chunk: - free_extent_buffer(fs_info->chunk_root->node); + return fs_info; + +out_failed: + if (partial) + return fs_info; + + if (fs_info->csum_root) + free_extent_buffer(fs_info->csum_root->node); + if (fs_info->dev_root) + free_extent_buffer(fs_info->dev_root->node); + if (fs_info->extent_root) + free_extent_buffer(fs_info->extent_root->node); + if (fs_info->tree_root) + free_extent_buffer(fs_info->tree_root->node); + if (fs_info->chunk_root) + free_extent_buffer(fs_info->chunk_root->node); out_devices: close_all_devices(fs_info); out_cleanup: @@ -833,10 +844,12 @@ out: return NULL; } -struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes) +struct btrfs_fs_info *open_ctree_fs_info(const char *filename, + u64 sb_bytenr, int writes, + int partial) { int fp; - struct btrfs_root *root; + struct btrfs_fs_info *info; int flags = O_CREAT | O_RDWR; if (!writes) @@ -847,33 +860,50 @@ struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes) fprintf (stderr, "Could not open %s\n", filename); return NULL; } - root = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes); + info = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes, partial); close(fp); + return info; +} - return root; +struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes) +{ + struct btrfs_fs_info *info; + + info = open_ctree_fs_info(filename, sb_bytenr, writes, 0); + if (!info) + return NULL; + return info->fs_root; } struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr, u64 root_tree_bytenr) { int fp; - struct btrfs_root *root; + struct btrfs_fs_info *info; + fp = open(filename, O_RDONLY); if (fp < 0) { fprintf (stderr, "Could not open %s\n", filename); return NULL; } - root = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, 0); + info = __open_ctree_fd(fp, filename, sb_bytenr, + root_tree_bytenr, 0, 0); close(fp); - return root; + if (!info) + return NULL; + return info->fs_root; } struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, int writes) { - return __open_ctree_fd(fp, path, sb_bytenr, 0, writes); + struct btrfs_fs_info *info; + info = __open_ctree_fd(fp, path, sb_bytenr, 0, writes, 0); + if (!info) + return NULL; + return info->fs_root; } int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr) diff --git a/disk-io.h b/disk-io.h index 2048fcfc..53e9b17a 100644 --- a/disk-io.h +++ b/disk-io.h @@ -48,6 +48,9 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, int writes); struct btrfs_root *open_ctree_recovery(const char *filename, u64 sb_bytenr, u64 root_tree_bytenr); +struct btrfs_fs_info *open_ctree_fs_info(const char *filename, + u64 sb_bytenr, int writes, + int partial); 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/extent_io.c b/extent_io.c index 973e9181..9990338b 100644 --- a/extent_io.c +++ b/extent_io.c @@ -706,6 +706,9 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree, int extent_buffer_uptodate(struct extent_buffer *eb) { + if (!eb) + return 0; + if (eb->flags & EXTENT_UPTODATE) return 1; return 0;