btrfs-progs: allow zoned RAID

Allow for RAID levels 0, 1 and 10 on zoned devices if the RAID stripe tree
is used.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Johannes Thumshirn 2023-09-14 09:05:35 -07:00 committed by David Sterba
parent 81d6ecd5c2
commit b4ab282686
5 changed files with 113 additions and 10 deletions

View File

@ -190,6 +190,14 @@ static const struct btrfs_feature mkfs_features[] = {
VERSION_NULL(safe),
VERSION_NULL(default),
.desc = "new extent tree format"
} , {
.name = "raid-stripe-tree",
.incompat_flag = BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE,
.sysfs_name = NULL,
VERSION_TO_STRING2(compat, 6,7),
VERSION_NULL(safe),
VERSION_NULL(default),
.desc = "raid stripe tree"
},
#endif
/* Keep this one last */

View File

@ -103,7 +103,8 @@ static inline u32 __BTRFS_LEAF_DATA_SIZE(u32 nodesize)
BTRFS_FEATURE_INCOMPAT_RAID1C34 | \
BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \
BTRFS_FEATURE_INCOMPAT_ZONED | \
BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2)
BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 | \
BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE)
#else
#define BTRFS_FEATURE_INCOMPAT_SUPP \
(BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \

View File

@ -737,7 +737,7 @@ out:
return ret;
}
bool zoned_profile_supported(u64 map_type)
bool zoned_profile_supported(u64 map_type, bool rst)
{
bool data = (map_type & BTRFS_BLOCK_GROUP_DATA);
u64 flags = (map_type & BTRFS_BLOCK_GROUP_PROFILE_MASK);
@ -746,9 +746,37 @@ bool zoned_profile_supported(u64 map_type)
if (flags == 0)
return true;
/* We can support DUP on metadata */
#if EXPERIMENTAL
if (data) {
if ((flags & BTRFS_BLOCK_GROUP_DUP) && rst)
return true;
/* Data RAID1 needs a raid-stripe-tree. */
if ((flags & BTRFS_BLOCK_GROUP_RAID1_MASK) && rst)
return true;
/* Data RAID0 needs a raid-stripe-tree. */
if ((flags & BTRFS_BLOCK_GROUP_RAID0) && rst)
return true;
/* Data RAID10 needs a raid-stripe-tree. */
if ((flags & BTRFS_BLOCK_GROUP_RAID10) && rst)
return true;
} else {
/* We can support DUP on metadata/system. */
if (flags & BTRFS_BLOCK_GROUP_DUP)
return true;
/* We can support RAID1 on metadata/system. */
if (flags & BTRFS_BLOCK_GROUP_RAID1_MASK)
return true;
/* We can support RAID0 on metadata/system. */
if (flags & BTRFS_BLOCK_GROUP_RAID0)
return true;
/* We can support RAID10 on metadata/system. */
if (flags & BTRFS_BLOCK_GROUP_RAID10)
return true;
}
#else
if (!data && (flags & BTRFS_BLOCK_GROUP_DUP))
return true;
#endif
/* All other profiles are not supported yet */
return false;
@ -863,7 +891,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_fs_info *fs_info,
}
}
if (!zoned_profile_supported(map->type)) {
if (!zoned_profile_supported(map->type, !!fs_info->stripe_root)) {
error("zoned: profile %s not yet supported",
btrfs_group_profile_str(map->type));
ret = -EINVAL;

View File

@ -133,7 +133,7 @@ static inline bool btrfs_dev_is_empty_zone(struct btrfs_device *device, u64 pos)
return zinfo->zones[zno].cond == BLK_ZONE_COND_EMPTY;
}
bool zoned_profile_supported(u64 map_type);
bool zoned_profile_supported(u64 map_type, bool rst);
int btrfs_reset_dev_zone(int fd, struct blk_zone *zone);
u64 btrfs_find_allocatable_zones(struct btrfs_device *device, u64 hole_start,
u64 hole_end, u64 num_bytes);
@ -214,7 +214,7 @@ static inline int btrfs_wipe_temporary_sb(struct btrfs_fs_devices *fs_devices)
return 0;
}
static inline bool zoned_profile_supported(u64 map_type)
static inline bool zoned_profile_supported(u64 map_type, bool rst)
{
return false;
}

View File

@ -962,6 +962,36 @@ fail:
return ret;
}
static int setup_raid_stripe_tree_root(struct btrfs_fs_info *fs_info)
{
struct btrfs_trans_handle *trans;
struct btrfs_root *stripe_root;
struct btrfs_key key = {
.objectid = BTRFS_RAID_STRIPE_TREE_OBJECTID,
.type = BTRFS_ROOT_ITEM_KEY,
};
int ret;
trans = btrfs_start_transaction(fs_info->tree_root, 0);
if (IS_ERR(trans))
return PTR_ERR(trans);
stripe_root = btrfs_create_tree(trans, fs_info, &key);
if (IS_ERR(stripe_root)) {
ret = PTR_ERR(stripe_root);
btrfs_abort_transaction(trans, ret);
return ret;
}
fs_info->stripe_root = stripe_root;
add_root_to_dirty_list(stripe_root);
ret = btrfs_commit_transaction(trans, fs_info->tree_root);
if (ret)
return ret;
return 0;
}
/* Thread callback for device preparation */
static void *prepare_one_device(void *ctx)
{
@ -1472,11 +1502,39 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
if (ret)
goto error;
if (opt_zoned && (!zoned_profile_supported(BTRFS_BLOCK_GROUP_METADATA | metadata_profile) ||
!zoned_profile_supported(BTRFS_BLOCK_GROUP_DATA | data_profile))) {
#if EXPERIMENTAL
if (opt_zoned && device_count) {
switch (data_profile & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
case BTRFS_BLOCK_GROUP_DUP:
case BTRFS_BLOCK_GROUP_RAID1:
case BTRFS_BLOCK_GROUP_RAID1C3:
case BTRFS_BLOCK_GROUP_RAID1C4:
case BTRFS_BLOCK_GROUP_RAID0:
case BTRFS_BLOCK_GROUP_RAID10:
features.incompat_flags |= BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE;
break;
default:
break;
}
}
#endif
if (opt_zoned) {
u64 metadata = BTRFS_BLOCK_GROUP_METADATA | metadata_profile;
u64 data = BTRFS_BLOCK_GROUP_DATA | data_profile;
bool rst = false;
#if EXPERIMENTAL
if (features.incompat_flags & BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE)
rst = true;
#endif
if (!zoned_profile_supported(metadata, rst) ||
!zoned_profile_supported(data, rst)) {
error("zoned mode does not yet support RAID/DUP profiles, please specify '-d single -m single' manually");
goto error;
}
}
t_prepare = calloc(device_count, sizeof(*t_prepare));
prepare_ctx = calloc(device_count, sizeof(*prepare_ctx));
@ -1585,6 +1643,14 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
goto error;
}
if (features.incompat_flags & BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE) {
ret = setup_raid_stripe_tree_root(fs_info);
if (ret < 0) {
error("failed to initialize raid-stripe-tree: %d (%m)", ret);
goto out;
}
}
trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
errno = -PTR_ERR(trans);