From bffb42193524b984ec8407773a0997707bb20cbf Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sun, 5 Feb 2012 16:11:48 -0500 Subject: [PATCH 01/18] 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 | 90 ++++++++++++++++++++++++++++++++++++--------------------- disk-io.h | 3 ++ extent_io.c | 3 ++ 5 files changed, 107 insertions(+), 55 deletions(-) diff --git a/btrfsck.c b/btrfsck.c index 509ab72..40eb407 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; @@ -2846,11 +2847,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 2aeabfd..c497892 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 b0b9502..e9fdba8 100644 --- a/disk-io.c +++ b/disk-io.c @@ -445,8 +445,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); - if (!root->node) - return -ENOENT; + if (!extent_buffer_uptodate(root->node)) + return -EIO; + return 0; } @@ -473,7 +474,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; } @@ -603,9 +606,9 @@ 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, +static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, u64 root_tree_bytenr, int writes, - int use_earliest_bdev) + int use_earliest_bdev, int partial) { u32 sectorsize; u32 nodesize; @@ -742,7 +745,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; } @@ -754,7 +757,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, @@ -766,15 +769,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; @@ -782,7 +785,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; @@ -790,7 +793,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; @@ -806,23 +809,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: @@ -842,10 +850,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) @@ -856,33 +866,47 @@ 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, 0); + info = __open_ctree_fd(fp, filename, sb_bytenr, 0, writes, 0, 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, 0); + info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, 0, 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, int use_earliest_bdev) { - return __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev); + struct btrfs_fs_info *info; + info = __open_ctree_fd(fp, path, sb_bytenr, 0, writes, use_earliest_bdev, 0); + if (!info) + return NULL; + return info->fs_root; } struct btrfs_root *open_ctree_broken(int fd, const char *device) diff --git a/disk-io.h b/disk-io.h index 2b1fcd5..664cabd 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, int use_earliest_bdev); 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); 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); diff --git a/extent_io.c b/extent_io.c index 973e918..9990338 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; -- 1.7.6.233.gd79bc