btrfs-progs: Add support for tree block operations on fs_info without roots

Since open_ctree_fs_info() now may return a fs_info even without any
roots, modify functions like read_tree_block() to operate with such
fs_info.

This provides the basis for btrfs-find-root to operate on chunk tree
with corrupted fs.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
[ coding style adjustments, unified declarations ]
Signed-off-by: David Sterba <dsterba@suse.com>
master
Qu Wenruo 2016-02-22 14:59:55 +08:00 committed by David Sterba
parent 43318324d2
commit 9db13dca2f
5 changed files with 58 additions and 38 deletions

View File

@ -45,7 +45,7 @@ static struct extent_buffer *debug_corrupt_block(struct btrfs_root *root,
int num_copies; int num_copies;
int mirror_num = 1; int mirror_num = 1;
eb = btrfs_find_create_tree_block(root, bytenr, blocksize); eb = btrfs_find_create_tree_block(root->fs_info, bytenr, blocksize);
if (!eb) if (!eb)
return NULL; return NULL;

View File

@ -51,10 +51,12 @@ static u32 max_nritems(u8 level, u32 nodesize)
sizeof(struct btrfs_key_ptr)); sizeof(struct btrfs_key_ptr));
} }
static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) static int check_tree_block(struct btrfs_fs_info *fs_info,
struct extent_buffer *buf)
{ {
struct btrfs_fs_devices *fs_devices; struct btrfs_fs_devices *fs_devices;
u32 leafsize = btrfs_super_leafsize(fs_info->super_copy);
int ret = BTRFS_BAD_FSID; int ret = BTRFS_BAD_FSID;
if (buf->start != btrfs_header_bytenr(buf)) if (buf->start != btrfs_header_bytenr(buf))
@ -62,12 +64,12 @@ static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
if (btrfs_header_level(buf) >= BTRFS_MAX_LEVEL) if (btrfs_header_level(buf) >= BTRFS_MAX_LEVEL)
return BTRFS_BAD_LEVEL; return BTRFS_BAD_LEVEL;
if (btrfs_header_nritems(buf) > max_nritems(btrfs_header_level(buf), if (btrfs_header_nritems(buf) > max_nritems(btrfs_header_level(buf),
root->nodesize)) leafsize))
return BTRFS_BAD_NRITEMS; return BTRFS_BAD_NRITEMS;
fs_devices = root->fs_info->fs_devices; fs_devices = fs_info->fs_devices;
while (fs_devices) { while (fs_devices) {
if (root->fs_info->ignore_fsid_mismatch || if (fs_info->ignore_fsid_mismatch ||
!memcmp_extent_buffer(buf, fs_devices->fsid, !memcmp_extent_buffer(buf, fs_devices->fsid,
btrfs_header_fsid(), btrfs_header_fsid(),
BTRFS_FSID_SIZE)) { BTRFS_FSID_SIZE)) {
@ -79,7 +81,7 @@ static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
return ret; return ret;
} }
static void print_tree_block_error(struct btrfs_root *root, static void print_tree_block_error(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb, struct extent_buffer *eb,
int err) int err)
{ {
@ -92,7 +94,7 @@ static void print_tree_block_error(struct btrfs_root *root,
read_extent_buffer(eb, buf, btrfs_header_fsid(), read_extent_buffer(eb, buf, btrfs_header_fsid(),
BTRFS_UUID_SIZE); BTRFS_UUID_SIZE);
uuid_unparse(buf, found_uuid); uuid_unparse(buf, found_uuid);
uuid_unparse(root->fs_info->fsid, fs_uuid); uuid_unparse(fs_info->fsid, fs_uuid);
fprintf(stderr, "fsid mismatch, want=%s, have=%s\n", fprintf(stderr, "fsid mismatch, want=%s, have=%s\n",
fs_uuid, found_uuid); fs_uuid, found_uuid);
break; break;
@ -157,14 +159,20 @@ int verify_tree_block_csum_silent(struct extent_buffer *buf, u16 csum_size)
return __csum_tree_block_size(buf, csum_size, 1, 1); return __csum_tree_block_size(buf, csum_size, 1, 1);
} }
static int csum_tree_block_fs_info(struct btrfs_fs_info *fs_info,
struct extent_buffer *buf, int verify)
{
u16 csum_size =
btrfs_super_csum_size(fs_info->super_copy);
if (verify && fs_info->suppress_check_block_errors)
return verify_tree_block_csum_silent(buf, csum_size);
return csum_tree_block_size(buf, csum_size, verify);
}
int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
int verify) int verify)
{ {
u16 csum_size = return csum_tree_block_fs_info(root->fs_info, buf, verify);
btrfs_super_csum_size(root->fs_info->super_copy);
if (verify && root->fs_info->suppress_check_block_errors)
return verify_tree_block_csum_silent(buf, csum_size);
return csum_tree_block_size(buf, csum_size, verify);
} }
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
@ -174,11 +182,10 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
bytenr, blocksize); bytenr, blocksize);
} }
struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, struct extent_buffer* btrfs_find_create_tree_block(
u64 bytenr, u32 blocksize) struct btrfs_fs_info *fs_info, u64 bytenr, u32 blocksize)
{ {
return alloc_extent_buffer(&root->fs_info->extent_cache, bytenr, return alloc_extent_buffer(&fs_info->extent_cache, bytenr, blocksize);
blocksize);
} }
void readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, void readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
@ -294,8 +301,9 @@ int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirr
return 0; return 0;
} }
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, struct extent_buffer* read_tree_block_fs_info(
u32 blocksize, u64 parent_transid) struct btrfs_fs_info *fs_info, u64 bytenr, u32 blocksize,
u64 parent_transid)
{ {
int ret; int ret;
struct extent_buffer *eb; struct extent_buffer *eb;
@ -305,7 +313,7 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
int num_copies; int num_copies;
int ignore = 0; int ignore = 0;
eb = btrfs_find_create_tree_block(root, bytenr, blocksize); eb = btrfs_find_create_tree_block(fs_info, bytenr, blocksize);
if (!eb) if (!eb)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
@ -313,33 +321,33 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
return eb; return eb;
while (1) { while (1) {
ret = read_whole_eb(root->fs_info, eb, mirror_num); ret = read_whole_eb(fs_info, eb, mirror_num);
if (ret == 0 && csum_tree_block(root, eb, 1) == 0 && if (ret == 0 && csum_tree_block_fs_info(fs_info, eb, 1) == 0 &&
check_tree_block(root, eb) == 0 && check_tree_block(fs_info, eb) == 0 &&
verify_parent_transid(eb->tree, eb, parent_transid, ignore) verify_parent_transid(eb->tree, eb, parent_transid, ignore)
== 0) { == 0) {
if (eb->flags & EXTENT_BAD_TRANSID && if (eb->flags & EXTENT_BAD_TRANSID &&
list_empty(&eb->recow)) { list_empty(&eb->recow)) {
list_add_tail(&eb->recow, list_add_tail(&eb->recow,
&root->fs_info->recow_ebs); &fs_info->recow_ebs);
eb->refs++; eb->refs++;
} }
btrfs_set_buffer_uptodate(eb); btrfs_set_buffer_uptodate(eb);
return eb; return eb;
} }
if (ignore) { if (ignore) {
if (check_tree_block(root, eb)) { if (check_tree_block(fs_info, eb)) {
if (!root->fs_info->suppress_check_block_errors) if (!fs_info->suppress_check_block_errors)
print_tree_block_error(root, eb, print_tree_block_error(fs_info, eb,
check_tree_block(root, eb)); check_tree_block(fs_info, eb));
} else { } else {
if (!root->fs_info->suppress_check_block_errors) if (!fs_info->suppress_check_block_errors)
fprintf(stderr, "Csum didn't match\n"); fprintf(stderr, "Csum didn't match\n");
} }
ret = -EIO; ret = -EIO;
break; break;
} }
num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, num_copies = btrfs_num_copies(&fs_info->mapping_tree,
eb->start, eb->len); eb->start, eb->len);
if (num_copies == 1) { if (num_copies == 1) {
ignore = 1; ignore = 1;
@ -431,8 +439,9 @@ int write_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_buffer *eb) struct extent_buffer *eb)
{ {
if (check_tree_block(root, eb)) { if (check_tree_block(root->fs_info, eb)) {
print_tree_block_error(root, eb, check_tree_block(root, eb)); print_tree_block_error(root->fs_info, eb,
check_tree_block(root->fs_info, eb));
BUG(); BUG();
} }
@ -938,7 +947,7 @@ static int setup_root_or_create_block(struct btrfs_fs_info *fs_info,
* million of places that assume a root has a valid ->node * million of places that assume a root has a valid ->node
*/ */
info_root->node = info_root->node =
btrfs_find_create_tree_block(info_root, 0, leafsize); btrfs_find_create_tree_block(fs_info, 0, leafsize);
if (!info_root->node) if (!info_root->node)
return -ENOMEM; return -ENOMEM;
clear_extent_buffer_uptodate(NULL, info_root->node); clear_extent_buffer_uptodate(NULL, info_root->node);

View File

@ -75,14 +75,23 @@ static inline u64 btrfs_sb_offset(int mirror)
struct btrfs_device; struct btrfs_device;
int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirror); int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirror);
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, struct extent_buffer* read_tree_block_fs_info(
u32 blocksize, u64 parent_transid); struct btrfs_fs_info *fs_info, u64 bytenr, u32 blocksize,
u64 parent_transid);
static inline struct extent_buffer* read_tree_block(
struct btrfs_root *root, u64 bytenr, u32 blocksize,
u64 parent_transid)
{
return read_tree_block_fs_info(root->fs_info, bytenr, blocksize,
parent_transid);
}
int read_extent_data(struct btrfs_root *root, char *data, u64 logical, int read_extent_data(struct btrfs_root *root, char *data, u64 logical,
u64 *len, int mirror); u64 *len, int mirror);
void readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, void readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
u64 parent_transid); u64 parent_transid);
struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, struct extent_buffer* btrfs_find_create_tree_block(
u64 bytenr, u32 blocksize); struct btrfs_fs_info *fs_info, u64 bytenr, u32 blocksize);
int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
u32 stripesize, struct btrfs_root *root, u32 stripesize, struct btrfs_root *root,

View File

@ -2822,7 +2822,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
buf = btrfs_find_create_tree_block(root, ins.objectid, blocksize); buf = btrfs_find_create_tree_block(root->fs_info, ins.objectid,
blocksize);
if (!buf) { if (!buf) {
btrfs_free_extent(trans, root, ins.objectid, ins.offset, btrfs_free_extent(trans, root, ins.objectid, ins.offset,
0, root->root_key.objectid, level, 0); 0, root->root_key.objectid, level, 0);

View File

@ -1840,7 +1840,8 @@ int btrfs_read_sys_array(struct btrfs_root *root)
u32 cur_offset; u32 cur_offset;
struct btrfs_key key; struct btrfs_key key;
sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET, sb = btrfs_find_create_tree_block(root->fs_info,
BTRFS_SUPER_INFO_OFFSET,
BTRFS_SUPER_INFO_SIZE); BTRFS_SUPER_INFO_SIZE);
if (!sb) if (!sb)
return -ENOMEM; return -ENOMEM;