btrfs-progs: check: add helper to reinit the root based on a key

In the case of per-bg roots we may be missing the root items.  To
re-initialize them we want to add the root item as well as allocate the
empty block.  To achieve this extract out the reinit root logic to a
helper that just takes the root key and then does the appropriate work
to allocate an empty root and update the root item.  Fix the normal
reinit root helper to use this new helper.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Josef Bacik 2022-03-07 17:10:55 -05:00 committed by David Sterba
parent f9b65a54c0
commit 37d05e9b1e

View File

@ -9129,29 +9129,34 @@ static int do_check_chunks_and_extents(void)
return ret;
}
static int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
static struct extent_buffer *btrfs_fsck_clear_root(
struct btrfs_trans_handle *trans,
struct btrfs_key *key)
{
struct btrfs_root_item ri = {};
struct btrfs_path *path;
struct extent_buffer *c;
struct extent_buffer *old = root->node;
int level;
struct btrfs_disk_key disk_key = {};
int ret;
struct btrfs_disk_key disk_key = {0,0,0};
level = 0;
path = btrfs_alloc_path();
if (!path)
return ERR_PTR(-ENOMEM);
c = btrfs_alloc_free_block(trans, root, gfs_info->nodesize,
root->root_key.objectid,
&disk_key, level, 0, 0);
if (IS_ERR(c))
return PTR_ERR(c);
c = btrfs_alloc_free_block(trans, gfs_info->tree_root,
gfs_info->nodesize, key->objectid,
&disk_key, 0, 0, 0);
if (IS_ERR(c)) {
btrfs_free_path(path);
return c;
}
memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_level(c, level);
btrfs_set_header_level(c, 0);
btrfs_set_header_bytenr(c, c->start);
btrfs_set_header_generation(c, trans->transid);
btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(c, root->root_key.objectid);
btrfs_set_header_owner(c, key->objectid);
write_extent_buffer(c, gfs_info->fs_devices->metadata_uuid,
btrfs_header_fsid(), BTRFS_FSID_SIZE);
@ -9161,25 +9166,48 @@ static int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
BTRFS_UUID_SIZE);
btrfs_mark_buffer_dirty(c);
/*
* this case can happen in the following case:
*
* reinit reloc data root, this is because we skip pin
* down reloc data tree before which means we can allocate
* same block bytenr here.
* The root item may not exist, try to insert an empty one so it exists,
* otherwise simply update the existing one with the correct settings.
*/
if (old->start == c->start) {
btrfs_set_root_generation(&root->root_item,
trans->transid);
root->root_item.level = btrfs_header_level(root->node);
ret = btrfs_update_root(trans, gfs_info->tree_root,
&root->root_key, &root->root_item);
if (ret) {
free_extent_buffer(c);
return ret;
}
ret = btrfs_insert_empty_item(trans, gfs_info->tree_root, path, key,
sizeof(ri));
if (ret == -EEXIST) {
read_extent_buffer(path->nodes[0], &ri,
btrfs_item_ptr_offset(path->nodes[0],
path->slots[0]),
sizeof(ri));
} else if (ret) {
btrfs_free_path(path);
free_extent_buffer(c);
return ERR_PTR(ret);
}
free_extent_buffer(old);
btrfs_set_root_bytenr(&ri, c->start);
btrfs_set_root_generation(&ri, trans->transid);
btrfs_set_root_refs(&ri, 1);
btrfs_set_root_used(&ri, c->len);
btrfs_set_root_generation_v2(&ri, trans->transid);
write_extent_buffer(path->nodes[0], &ri,
btrfs_item_ptr_offset(path->nodes[0],
path->slots[0]),
sizeof(ri));
btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_free_path(path);
return c;
}
static int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
struct extent_buffer *c;
c = btrfs_fsck_clear_root(trans, &root->root_key);
if (IS_ERR(c))
return PTR_ERR(c);
free_extent_buffer(root->node);
root->node = c;
add_root_to_dirty_list(root);
return 0;