btrfs-progs: mkfs: add support for the block group tree

Add the extent tree v2 table with the block group tree as a root, and
then create the empty root and use the proper root for cleanup up the
temporary block groups.

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:51 -05:00 committed by David Sterba
parent c7a8363276
commit 7e3bf7fc44
3 changed files with 91 additions and 19 deletions

View File

@ -39,6 +39,7 @@ static u64 reference_root_table[] = {
[MKFS_FS_TREE] = BTRFS_FS_TREE_OBJECTID,
[MKFS_CSUM_TREE] = BTRFS_CSUM_TREE_OBJECTID,
[MKFS_FREE_SPACE_TREE] = BTRFS_FREE_SPACE_TREE_OBJECTID,
[MKFS_BLOCK_GROUP_TREE] = BTRFS_BLOCK_GROUP_TREE_OBJECTID,
};
static int btrfs_write_empty_tree(int fd, struct btrfs_mkfs_config *cfg,
@ -97,7 +98,8 @@ static int btrfs_create_tree_root(int fd, struct btrfs_mkfs_config *cfg,
for (i = 0; i < blocks_nr; i++) {
blk = blocks[i];
if (blk == MKFS_ROOT_TREE || blk == MKFS_CHUNK_TREE)
if (blk == MKFS_ROOT_TREE || blk == MKFS_CHUNK_TREE ||
blk == MKFS_BLOCK_GROUP_TREE)
continue;
btrfs_set_root_bytenr(&root_item, cfg->blocks[blk]);
@ -187,6 +189,50 @@ static int create_free_space_tree(int fd, struct btrfs_mkfs_config *cfg,
return 0;
}
static void write_block_group_item(struct extent_buffer *buf, u32 nr,
u64 objectid, u64 offset, u64 used,
u32 itemoff)
{
struct btrfs_block_group_item *bg_item;
struct btrfs_disk_key disk_key;
btrfs_set_disk_key_objectid(&disk_key, objectid);
btrfs_set_disk_key_offset(&disk_key, offset);
btrfs_set_disk_key_type(&disk_key, BTRFS_BLOCK_GROUP_ITEM_KEY);
btrfs_set_item_key(buf, &disk_key, nr);
btrfs_set_item_offset(buf, nr, itemoff);
btrfs_set_item_size(buf, nr, sizeof(*bg_item));
bg_item = btrfs_item_ptr(buf, nr, struct btrfs_block_group_item);
btrfs_set_block_group_used(buf, bg_item, used);
btrfs_set_block_group_flags(buf, bg_item, BTRFS_BLOCK_GROUP_SYSTEM);
btrfs_set_block_group_chunk_objectid(buf, bg_item,
BTRFS_FIRST_CHUNK_TREE_OBJECTID);
}
static int create_block_group_tree(int fd, struct btrfs_mkfs_config *cfg,
struct extent_buffer *buf,
u64 bg_offset, u64 bg_size, u64 bg_used)
{
int ret;
memset(buf->data + sizeof(struct btrfs_header), 0,
cfg->nodesize - sizeof(struct btrfs_header));
write_block_group_item(buf, 0, bg_offset, bg_size, bg_used,
cfg->leaf_data_size -
sizeof(struct btrfs_block_group_item));
btrfs_set_header_bytenr(buf, cfg->blocks[MKFS_BLOCK_GROUP_TREE]);
btrfs_set_header_owner(buf, BTRFS_BLOCK_GROUP_TREE_OBJECTID);
btrfs_set_header_nritems(buf, 1);
csum_tree_block_size(buf, btrfs_csum_type_size(cfg->csum_type), 0,
cfg->csum_type);
ret = pwrite(fd, buf->data, cfg->nodesize,
cfg->blocks[MKFS_BLOCK_GROUP_TREE]);
if (ret != cfg->nodesize)
return ret < 0 ? -errno : -EIO;
return 0;
}
/*
* @fs_uuid - if NULL, generates a UUID, returns back the new filesystem UUID
*
@ -239,11 +285,19 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
bool add_block_group = true;
bool free_space_tree = !!(cfg->runtime_features &
BTRFS_RUNTIME_FEATURE_FREE_SPACE_TREE);
bool extent_tree_v2 = !!(cfg->features &
BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2);
/* Don't include the free space tree in the blocks to process. */
if (!free_space_tree)
blocks_nr--;
if (extent_tree_v2) {
blocks = extent_tree_v2_blocks;
blocks_nr = ARRAY_SIZE(extent_tree_v2_blocks);
add_block_group = false;
}
if ((cfg->features & BTRFS_FEATURE_INCOMPAT_ZONED)) {
system_group_offset = cfg->zone_size * BTRFS_NR_SB_LOG_ZONES;
system_group_size = cfg->zone_size;
@ -300,6 +354,12 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
btrfs_set_super_compat_ro_flags(&super, ro_flags);
btrfs_set_super_cache_generation(&super, 0);
}
if (extent_tree_v2) {
btrfs_set_super_block_group_root(&super,
cfg->blocks[MKFS_BLOCK_GROUP_TREE]);
btrfs_set_super_block_group_root_generation(&super, 1);
btrfs_set_super_block_group_root_level(&super, 0);
}
if (cfg->label)
__strncpy_null(super.label, cfg->label, BTRFS_LABEL_SIZE - 1);
@ -331,25 +391,12 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
/* Add the block group item for our temporary chunk. */
if (cfg->blocks[blk] > system_group_offset && add_block_group) {
struct btrfs_block_group_item *bg_item;
itemoff -= sizeof(struct btrfs_block_group_item);
write_block_group_item(buf, nritems,
system_group_offset,
system_group_size, total_used,
itemoff);
add_block_group = false;
itemoff -= sizeof(*bg_item);
btrfs_set_disk_key_objectid(&disk_key, system_group_offset);
btrfs_set_disk_key_offset(&disk_key, system_group_size);
btrfs_set_disk_key_type(&disk_key, BTRFS_BLOCK_GROUP_ITEM_KEY);
btrfs_set_item_key(buf, &disk_key, nritems);
btrfs_set_item_offset(buf, nritems, itemoff);
btrfs_set_item_size(buf, nritems, sizeof(*bg_item));
bg_item = btrfs_item_ptr(buf, nritems,
struct btrfs_block_group_item);
btrfs_set_block_group_used(buf, bg_item, total_used);
btrfs_set_block_group_flags(buf, bg_item,
BTRFS_BLOCK_GROUP_SYSTEM);
btrfs_set_block_group_chunk_objectid(buf, bg_item,
BTRFS_FIRST_CHUNK_TREE_OBJECTID);
nritems++;
}
@ -565,6 +612,14 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
goto out;
}
if (extent_tree_v2) {
ret = create_block_group_tree(fd, cfg, buf,
system_group_offset,
system_group_size, total_used);
if (ret)
goto out;
}
/* and write out the super block */
memset(buf->data, 0, BTRFS_SUPER_INFO_SIZE);
memcpy(buf->data, &super, sizeof(super));

View File

@ -51,6 +51,7 @@ enum btrfs_mkfs_block {
MKFS_FS_TREE,
MKFS_CSUM_TREE,
MKFS_FREE_SPACE_TREE,
MKFS_BLOCK_GROUP_TREE,
MKFS_BLOCK_COUNT
};
@ -69,6 +70,17 @@ static const enum btrfs_mkfs_block extent_tree_v1_blocks[] = {
MKFS_FREE_SPACE_TREE,
};
static const enum btrfs_mkfs_block extent_tree_v2_blocks[] = {
MKFS_ROOT_TREE,
MKFS_EXTENT_TREE,
MKFS_CHUNK_TREE,
MKFS_DEV_TREE,
MKFS_FS_TREE,
MKFS_CSUM_TREE,
MKFS_FREE_SPACE_TREE,
MKFS_BLOCK_GROUP_TREE,
};
struct btrfs_mkfs_config {
/* Label of the new filesystem */
const char *label;

View File

@ -299,6 +299,11 @@ static int recow_roots(struct btrfs_trans_handle *trans,
ret = __recow_root(trans, info->dev_root);
if (ret)
return ret;
if (btrfs_fs_incompat(info, EXTENT_TREE_V2)) {
ret = __recow_root(trans, info->block_group_root);
if (ret)
return ret;
}
ret = recow_global_roots(trans);
if (ret)
return ret;