#define BTRFS_FEATURE_COMPAT_RO_SUPP                   \
        (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE |      \
         BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID | \
-        BTRFS_FEATURE_COMPAT_RO_VERITY)
+        BTRFS_FEATURE_COMPAT_RO_VERITY |               \
+        BTRFS_FEATURE_COMPAT_RO_BLOCK_GROUP_TREE)
 
 #define BTRFS_FEATURE_COMPAT_RO_SAFE_SET       0ULL
 #define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR     0ULL
 
        btrfs_set_backup_chunk_root_level(root_backup,
                               btrfs_header_level(info->chunk_root->node));
 
-       if (!btrfs_fs_incompat(info, EXTENT_TREE_V2)) {
+       if (!btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE)) {
                struct btrfs_root *extent_root = btrfs_extent_root(info, 0);
                struct btrfs_root *csum_root = btrfs_csum_root(info, 0);
 
        location.type = BTRFS_ROOT_ITEM_KEY;
        location.offset = 0;
 
-       if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) {
+       if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE)) {
                location.objectid = BTRFS_BLOCK_GROUP_TREE_OBJECTID;
                root = btrfs_read_tree_root(tree_root, &location);
                if (IS_ERR(root)) {
                ret = -EINVAL;
        }
 
+       /*
+        * Artificial requirement for block-group-tree to force newer features
+        * (free-space-tree, no-holes) so the test matrix is smaller.
+        */
+       if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE) &&
+           (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID) ||
+            !btrfs_fs_incompat(fs_info, NO_HOLES))) {
+               btrfs_err(fs_info,
+               "block-group-tree feature requires fres-space-tree and no-holes");
+               ret = -EINVAL;
+       }
+
        if (memcmp(fs_info->fs_devices->metadata_uuid, sb->dev_item.fsid,
                   BTRFS_FSID_SIZE) != 0) {
                btrfs_err(fs_info,
        int ret = 0;
        int i;
 
-       if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) {
-               struct btrfs_root *root;
-
-               root = btrfs_alloc_root(fs_info, BTRFS_BLOCK_GROUP_TREE_OBJECTID,
-                                       GFP_KERNEL);
-               if (!root)
-                       return -ENOMEM;
-               fs_info->block_group_root = root;
-       }
-
        for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) {
                if (handle_error) {
                        if (!IS_ERR(tree_root->node))
 
 
 static inline struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info)
 {
-       if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2))
+       if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE))
                return fs_info->block_group_root;
        return btrfs_extent_root(fs_info, 0);
 }
 
 BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES);
 BTRFS_FEAT_ATTR_INCOMPAT(metadata_uuid, METADATA_UUID);
 BTRFS_FEAT_ATTR_COMPAT_RO(free_space_tree, FREE_SPACE_TREE);
+BTRFS_FEAT_ATTR_COMPAT_RO(block_group_tree, BLOCK_GROUP_TREE);
 BTRFS_FEAT_ATTR_INCOMPAT(raid1c34, RAID1C34);
 #ifdef CONFIG_BLK_DEV_ZONED
 BTRFS_FEAT_ATTR_INCOMPAT(zoned, ZONED);
        BTRFS_FEAT_ATTR_PTR(metadata_uuid),
        BTRFS_FEAT_ATTR_PTR(free_space_tree),
        BTRFS_FEAT_ATTR_PTR(raid1c34),
+       BTRFS_FEAT_ATTR_PTR(block_group_tree),
 #ifdef CONFIG_BLK_DEV_ZONED
        BTRFS_FEAT_ATTR_PTR(zoned),
 #endif
 
 #define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID  (1ULL << 1)
 #define BTRFS_FEATURE_COMPAT_RO_VERITY                 (1ULL << 2)
 
+/*
+ * Put all block group items into a dedicated block group tree, greatly
+ * reducing mount time for large filesystem due to better locality.
+ */
+#define BTRFS_FEATURE_COMPAT_RO_BLOCK_GROUP_TREE       (1ULL << 3)
+
 #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF   (1ULL << 0)
 #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL  (1ULL << 1)
 #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS    (1ULL << 2)