Add open_ctree_fs_info for partial FS opens
authorChris Mason <chris.mason@oracle.com>
Sun, 5 Feb 2012 21:11:48 +0000 (16:11 -0500)
committerChris Mason <chris.mason@oracle.com>
Sun, 5 Feb 2012 21:11:48 +0000 (16:11 -0500)
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 <chris.mason@oracle.com>
btrfsck.c
debug-tree.c
disk-io.c
disk-io.h
extent_io.c

index 3a23e66..a56bb4b 100644 (file)
--- 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;
index 2aeabfd..c497892 100644 (file)
@@ -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;
index 408b2d5..58aec02 100644 (file)
--- 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)
index 2048fcf..53e9b17 100644 (file)
--- 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,
index 973e918..9990338 100644 (file)
@@ -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;