forked from Mirrors/btrfs-progs
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
parent
43318324d2
commit
9db13dca2f
|
@ -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;
|
||||||
|
|
||||||
|
|
71
disk-io.c
71
disk-io.c
|
@ -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);
|
||||||
|
|
17
disk-io.h
17
disk-io.h
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue