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>
master
Chris Mason 2012-02-05 16:11:48 -05:00
parent 6cd813b6fc
commit e7580bb296
5 changed files with 112 additions and 54 deletions

View File

@ -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;

View 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;

View File

@ -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)

View File

@ -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,

View 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;