diff --git a/mkfs/common.c b/mkfs/common.c index 11d92c8b..aa65543b 100644 --- a/mkfs/common.c +++ b/mkfs/common.c @@ -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)); diff --git a/mkfs/common.h b/mkfs/common.h index 428cd366..3533e114 100644 --- a/mkfs/common.h +++ b/mkfs/common.h @@ -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; diff --git a/mkfs/main.c b/mkfs/main.c index 20dc0436..7f79ba1a 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -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;