410 lines
12 KiB
Diff
410 lines
12 KiB
Diff
|
From bffb42193524b984ec8407773a0997707bb20cbf Mon Sep 17 00:00:00 2001
|
||
|
From: Chris Mason <chris.mason@oracle.com>
|
||
|
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 <chris.mason@oracle.com>
|
||
|
---
|
||
|
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
|
||
|
|