Upstream-Status: Inappropriate [Backport]
From 238f88bb6c4b9ebad727c6bffb57f542e7e412c1 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Sun, 19 Dec 2010 16:22:31 -0500
Subject: [PATCH 4/5] Allow partial FS opens for btrfsck scanning

Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
 btrfsck.c |   10 ++++++++--
 convert.c |   20 ++++++++++++++------
 disk-io.c |   57 +++++++++++++++++++++++++++++++++++++++++----------------
 disk-io.h |    5 +++--
 4 files changed, 66 insertions(+), 26 deletions(-)

diff --git a/btrfsck.c b/btrfsck.c
index 63e44d1..f760706 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -2820,6 +2820,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;
@@ -2856,11 +2857,16 @@ int main(int ac, char **av)
 		return -EBUSY;
 	}
 
-	root = open_ctree(av[optind], bytenr, 0);
+	info = open_fs_info(av[optind], bytenr, 0, 1);
 
-	if (root == NULL)
+	if (info == NULL)
 		return 1;
 
+	root = info->fs_root;
+	if (!root) {
+		fprintf(stderr, "failed to read the filesystem\n");
+		exit(1);
+	}
 	ret = check_extents(root);
 	if (ret)
 		goto out;
diff --git a/convert.c b/convert.c
index fbcf4a3..72e3cdc 100644
--- a/convert.c
+++ b/convert.c
@@ -2342,6 +2342,7 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
 	ext2_filsys ext2_fs;
 	struct btrfs_root *root;
 	struct btrfs_root *ext2_root;
+	struct btrfs_fs_info *fs_info;
 
 	ret = open_ext2fs(devname, &ext2_fs);
 	if (ret) {
@@ -2386,11 +2387,12 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
 		fprintf(stderr, "unable to update system chunk\n");
 		goto fail;
 	}
-	root = open_ctree_fd(fd, devname, super_bytenr, O_RDWR);
-	if (!root) {
+	fs_info = open_ctree_fd(fd, devname, super_bytenr, O_RDWR, 0);
+	if (!fs_info) {
 		fprintf(stderr, "unable to open ctree\n");
 		goto fail;
 	}
+	root = fs_info->fs_root;
 	ret = cache_free_extents(root, ext2_fs);
 	if (ret) {
 		fprintf(stderr, "error during cache_free_extents %d\n", ret);
@@ -2447,11 +2449,13 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
 		goto fail;
 	}
 
-	root = open_ctree_fd(fd, devname, 0, O_RDWR);
-	if (!root) {
+	fs_info = open_ctree_fd(fd, devname, 0, O_RDWR, 0);
+	if (!fs_info) {
 		fprintf(stderr, "unable to open ctree\n");
 		goto fail;
 	}
+	root = fs_info->fs_root;
+
 	/* move chunk tree into system chunk. */
 	ret = fixup_chunk_mapping(root);
 	if (ret) {
@@ -2525,6 +2529,7 @@ int do_rollback(const char *devname, int force)
 	struct btrfs_key key;
 	struct btrfs_path path;
 	struct extent_io_tree io_tree;
+	struct btrfs_fs_info *fs_info;
 	char *buf;
 	char *name;
 	u64 bytenr;
@@ -2546,11 +2551,14 @@ int do_rollback(const char *devname, int force)
 		fprintf(stderr, "unable to open %s\n", devname);
 		goto fail;
 	}
-	root = open_ctree_fd(fd, devname, 0, O_RDWR);
-	if (!root) {
+
+	fs_info = open_ctree_fd(fd, devname, 0, O_RDWR, 0);
+	if (!fs_info) {
 		fprintf(stderr, "unable to open ctree\n");
 		goto fail;
 	}
+	root = fs_info->fs_root;
+
 	ret = may_rollback(root);
 	if (ret < 0) {
 		fprintf(stderr, "unable to do rollback\n");
diff --git a/disk-io.c b/disk-io.c
index f4368f3..dc100b0 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -441,7 +441,8 @@ 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 (!log_root->node)
+		return -EIO;
 	return 0;
 }
 
@@ -571,10 +572,11 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
 	return root;
 }
 
-struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
+struct btrfs_fs_info *open_fs_info(const char *filename, u64 sb_bytenr,
+				   int writes, int partial)
 {
 	int fp;
-	struct btrfs_root *root;
+	struct btrfs_fs_info *fs_info;
 	int flags = O_CREAT | O_RDWR;
 
 	if (!writes)
@@ -585,14 +587,25 @@ 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, writes);
+	fs_info = open_ctree_fd(fp, filename, sb_bytenr, writes, partial);
+
 	close(fp);
+	return fs_info;
+}
 
-	return root;
+
+struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
+{
+	struct btrfs_fs_info *fs_info;
+
+	fs_info = open_fs_info(filename, sb_bytenr, writes, 0);
+	if (fs_info)
+		return fs_info->fs_root;
+	return NULL;
 }
 
-struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
-				 int writes)
+struct btrfs_fs_info *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
+				    int writes, int partial)
 {
 	u32 sectorsize;
 	u32 nodesize;
@@ -727,7 +740,8 @@ 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);
-		BUG_ON(ret);
+		if (ret)
+			goto fail;
 	}
 
 	blocksize = btrfs_level_size(tree_root,
@@ -737,25 +751,32 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
 	tree_root->node = read_tree_block(tree_root,
 					  btrfs_super_root(disk_super),
 					  blocksize, generation);
-	BUG_ON(!tree_root->node);
+	if (!tree_root->node)
+		goto fail;
+
 	ret = find_and_setup_root(tree_root, fs_info,
 				  BTRFS_EXTENT_TREE_OBJECTID, extent_root);
-	BUG_ON(ret);
+	if (ret)
+		goto fail;
+
 	extent_root->track_dirty = 1;
 
 	ret = find_and_setup_root(tree_root, fs_info,
 				  BTRFS_DEV_TREE_OBJECTID, dev_root);
-	BUG_ON(ret);
+	if (ret)
+		goto fail;
+
 	dev_root->track_dirty = 1;
 
 	ret = find_and_setup_root(tree_root, fs_info,
 				  BTRFS_CSUM_TREE_OBJECTID, csum_root);
-	BUG_ON(ret);
+	if (ret)
+		goto fail;
 	csum_root->track_dirty = 1;
 
-	BUG_ON(ret);
-
-	find_and_setup_log_root(tree_root, fs_info, disk_super);
+	ret = find_and_setup_log_root(tree_root, fs_info, disk_super);
+	if (ret)
+		goto fail;
 
 	fs_info->generation = generation + 1;
 	btrfs_read_block_groups(fs_info->tree_root);
@@ -769,7 +790,11 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
 	fs_info->metadata_alloc_profile = (u64)-1;
 	fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
 
-	return fs_info->fs_root;
+	return fs_info;
+fail:
+	if (partial)
+		return fs_info;
+	return NULL;
 }
 
 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 7ebec24..03c5eee 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -44,8 +44,9 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
 int clean_tree_block(struct btrfs_trans_handle *trans,
 		     struct btrfs_root *root, struct extent_buffer *buf);
 struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes);
-struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
-				 int writes);
+struct btrfs_fs_info *open_fs_info(const char *filename, u64 sb_bytenr, int writes, int partial);
+struct btrfs_fs_info *open_ctree_fd(int fp, const char *path, 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,
-- 
1.7.2.3

