From 7e520022ff158f28d449f41e04304edf0dd15f03 Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Mon, 26 Apr 2021 15:27:22 +0900 Subject: [PATCH] btrfs-progs: zoned: check and enable ZONED mode Introduce function btrfs_check_zoned_mode() to check if ZONED flag is enabled on the file system and if the file system consists of zoned devices with equal zone size. Reviewed-by: Johannes Thumshirn Signed-off-by: Naohiro Aota Signed-off-by: David Sterba --- kernel-shared/ctree.h | 14 +++++++ kernel-shared/disk-io.c | 6 +++ kernel-shared/zoned.c | 85 +++++++++++++++++++++++++++++++++++++++++ kernel-shared/zoned.h | 1 + 4 files changed, 106 insertions(+) diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h index 77a5ad48..aab631a4 100644 --- a/kernel-shared/ctree.h +++ b/kernel-shared/ctree.h @@ -1213,8 +1213,22 @@ struct btrfs_fs_info { u32 nodesize; u32 sectorsize; u32 stripesize; + + /* + * Zone size > 0 when in ZONED mode, otherwise it's used for a check + * if the mode is enabled + */ + union { + u64 zone_size; + u64 zoned; + }; }; +static inline bool btrfs_is_zoned(const struct btrfs_fs_info *fs_info) +{ + return fs_info->zoned != 0; +} + /* * in ram representation of the tree. extent_root is used for all allocations * and for the extent tree extent_root root. diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c index 7af5d77b..36c1dd49 100644 --- a/kernel-shared/disk-io.c +++ b/kernel-shared/disk-io.c @@ -1325,6 +1325,12 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, struct open_ctree_flags *oc goto out_chunk; } + ret = btrfs_check_zoned_mode(fs_info); + if (ret) { + error("zoned: failed to initialize zoned mode: %d", ret); + goto out_chunk; + } + eb = fs_info->chunk_root->node; read_extent_buffer(eb, fs_info->chunk_tree_uuid, btrfs_header_chunk_tree_uuid(eb), diff --git a/kernel-shared/zoned.c b/kernel-shared/zoned.c index fdbfbf6f..99155a35 100644 --- a/kernel-shared/zoned.c +++ b/kernel-shared/zoned.c @@ -238,3 +238,88 @@ int btrfs_get_zone_info(int fd, const char *file, return 0; } + +int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info) +{ + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + struct btrfs_device *device; + u64 zoned_devices = 0; + u64 nr_devices = 0; + u64 zone_size = 0; + const bool incompat_zoned = btrfs_fs_incompat(fs_info, ZONED); + int ret = 0; + + /* Count zoned devices */ + list_for_each_entry(device, &fs_devices->devices, dev_list) { + enum btrfs_zoned_model model; + + if (device->fd == -1) + continue; + + model = zoned_model(device->name); + /* + * A Host-Managed zoned device must be used as a zoned device. + * A Host-Aware zoned device and a non-zoned devices can be + * treated as a zoned device, if ZONED flag is enabled in the + * superblock. + */ + if (model == ZONED_HOST_MANAGED || + (model == ZONED_HOST_AWARE && incompat_zoned) || + (model == ZONED_NONE && incompat_zoned)) { + struct btrfs_zoned_device_info *zone_info = + device->zone_info; + + zoned_devices++; + if (!zone_size) { + zone_size = zone_info->zone_size; + } else if (zone_info->zone_size != zone_size) { + error( + "zoned: unequal block device zone sizes: have %llu found %llu", + device->zone_info->zone_size, + zone_size); + ret = -EINVAL; + goto out; + } + } + nr_devices++; + } + + if (!zoned_devices && !incompat_zoned) + goto out; + + if (!zoned_devices && incompat_zoned) { + /* No zoned block device found on ZONED filesystem */ + error("zoned: no zoned devices found on a zoned filesystem"); + ret = -EINVAL; + goto out; + } + + if (zoned_devices && !incompat_zoned) { + error("zoned: mode not enabled but zoned device found"); + ret = -EINVAL; + goto out; + } + + if (zoned_devices != nr_devices) { + error("zoned: cannot mix zoned and regular devices"); + ret = -EINVAL; + goto out; + } + + /* + * stripe_size is always aligned to BTRFS_STRIPE_LEN in + * __btrfs_alloc_chunk(). Since we want stripe_len == zone_size, + * check the alignment here. + */ + if (!IS_ALIGNED(zone_size, BTRFS_STRIPE_LEN)) { + error("zoned: zone size %llu not aligned to stripe %u", + zone_size, BTRFS_STRIPE_LEN); + ret = -EINVAL; + goto out; + } + + fs_info->zone_size = zone_size; + +out: + return ret; +} diff --git a/kernel-shared/zoned.h b/kernel-shared/zoned.h index a5d6a466..54bece44 100644 --- a/kernel-shared/zoned.h +++ b/kernel-shared/zoned.h @@ -40,5 +40,6 @@ u64 zone_size(const char *file); int btrfs_get_zone_info(int fd, const char *file, struct btrfs_zoned_device_info **zinfo); int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info); +int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info); #endif /* __BTRFS_ZONED_H__ */