btrfs: zoned: refactor device checks in btrfs_check_zoned_mode
authorChristoph Hellwig <hch@lst.de>
Wed, 7 Sep 2022 09:22:14 +0000 (11:22 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 26 Sep 2022 10:28:02 +0000 (12:28 +0200)
btrfs_check_zoned_mode is really hard to follow, mostly due to the
fact that a lot of the checks use duplicate conditions after support
for zone emulation for conventional devices on file systems with the
ZONED flag was added.  Fix this by factoring out the check for host
managed devices for !ZONED file systems into a separate helper and
then simplifying the rest of the code.

Reviewed-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/zoned.c

index eff14ff..e2d073b 100644 (file)
@@ -652,80 +652,55 @@ int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
        return 0;
 }
 
+static int btrfs_check_for_zoned_device(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_device *device;
+
+       list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) {
+               if (device->bdev &&
+                   bdev_zoned_model(device->bdev) == BLK_ZONED_HM) {
+                       btrfs_err(fs_info,
+                               "zoned: mode not enabled but zoned device found: %pg",
+                               device->bdev);
+                       return -EINVAL;
+               }
+       }
+
+       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;
        u64 max_zone_append_size = 0;
-       const bool incompat_zoned = btrfs_fs_incompat(fs_info, ZONED);
-       int ret = 0;
+       int ret;
 
-       /* Count zoned devices */
-       list_for_each_entry(device, &fs_devices->devices, dev_list) {
-               enum blk_zoned_model model;
+       /*
+        * Host-Managed devices can't be used without the ZONED flag.  With the
+        * ZONED all devices can be used, using zone emulation if required.
+        */
+       if (!btrfs_fs_incompat(fs_info, ZONED))
+               return btrfs_check_for_zoned_device(fs_info);
+
+       list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) {
+               struct btrfs_zoned_device_info *zone_info = device->zone_info;
 
                if (!device->bdev)
                        continue;
 
-               model = bdev_zoned_model(device->bdev);
-               /*
-                * 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 == BLK_ZONED_HM ||
-                   (model == BLK_ZONED_HA && incompat_zoned) ||
-                   (model == BLK_ZONED_NONE && incompat_zoned)) {
-                       struct btrfs_zoned_device_info *zone_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) {
-                               btrfs_err(fs_info,
+               if (!zone_size) {
+                       zone_size = zone_info->zone_size;
+               } else if (zone_info->zone_size != zone_size) {
+                       btrfs_err(fs_info,
                "zoned: unequal block device zone sizes: have %llu found %llu",
-                                         device->zone_info->zone_size,
-                                         zone_size);
-                               ret = -EINVAL;
-                               goto out;
-                       }
-                       if (!max_zone_append_size ||
-                           (zone_info->max_zone_append_size &&
-                            zone_info->max_zone_append_size < max_zone_append_size))
-                               max_zone_append_size =
-                                       zone_info->max_zone_append_size;
+                                 zone_info->zone_size, zone_size);
+                       return -EINVAL;
                }
-               nr_devices++;
-       }
-
-       if (!zoned_devices && !incompat_zoned)
-               goto out;
-
-       if (!zoned_devices && incompat_zoned) {
-               /* No zoned block device found on ZONED filesystem */
-               btrfs_err(fs_info,
-                         "zoned: no zoned devices found on a zoned filesystem");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (zoned_devices && !incompat_zoned) {
-               btrfs_err(fs_info,
-                         "zoned: mode not enabled but zoned device found");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (zoned_devices != nr_devices) {
-               btrfs_err(fs_info,
-                         "zoned: cannot mix zoned and regular devices");
-               ret = -EINVAL;
-               goto out;
+               if (!max_zone_append_size ||
+                   (zone_info->max_zone_append_size &&
+                    zone_info->max_zone_append_size < max_zone_append_size))
+                       max_zone_append_size = zone_info->max_zone_append_size;
        }
 
        /*
@@ -737,14 +712,12 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
                btrfs_err(fs_info,
                          "zoned: zone size %llu not aligned to stripe %u",
                          zone_size, BTRFS_STRIPE_LEN);
-               ret = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        if (btrfs_fs_incompat(fs_info, MIXED_GROUPS)) {
                btrfs_err(fs_info, "zoned: mixed block groups not supported");
-               ret = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        fs_info->zone_size = zone_size;
@@ -760,11 +733,10 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
         */
        ret = btrfs_check_mountopts_zoned(fs_info);
        if (ret)
-               goto out;
+               return ret;
 
        btrfs_info(fs_info, "zoned mode enabled with zone size %llu", zone_size);
-out:
-       return ret;
+       return 0;
 }
 
 int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info)