diff --git a/check/main.c b/check/main.c index 054957f1..6ee3250e 100644 --- a/check/main.c +++ b/check/main.c @@ -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;