btrfs: zoned: factor out per-zone logic from btrfs_load_block_group_zone_info
authorChristoph Hellwig <hch@lst.de>
Mon, 5 Jun 2023 08:51:06 +0000 (10:51 +0200)
committerDavid Sterba <dsterba@suse.com>
Thu, 12 Oct 2023 14:44:08 +0000 (16:44 +0200)
Split out a helper for the body of the per-zone loop in
btrfs_load_block_group_zone_info to make the function easier to read and
modify.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/zoned.c

index 909f11e0e53b8bcc142c570714733ac3770b142d..838421f2918db3cb1dcc8132c63490d58694d4df 100644 (file)
@@ -1288,19 +1288,103 @@ struct zone_info {
        u64 alloc_offset;
 };
 
+static int btrfs_load_zone_info(struct btrfs_fs_info *fs_info, int zone_idx,
+                               struct zone_info *info, unsigned long *active,
+                               struct map_lookup *map)
+{
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       struct btrfs_device *device = map->stripes[zone_idx].dev;
+       int dev_replace_is_ongoing = 0;
+       unsigned int nofs_flag;
+       struct blk_zone zone;
+       int ret;
+
+       info->physical = map->stripes[zone_idx].physical;
+
+       if (!device->bdev) {
+               info->alloc_offset = WP_MISSING_DEV;
+               return 0;
+       }
+
+       /* Consider a zone as active if we can allow any number of active zones. */
+       if (!device->zone_info->max_active_zones)
+               __set_bit(zone_idx, active);
+
+       if (!btrfs_dev_is_sequential(device, info->physical)) {
+               info->alloc_offset = WP_CONVENTIONAL;
+               return 0;
+       }
+
+       /* This zone will be used for allocation, so mark this zone non-empty. */
+       btrfs_dev_clear_zone_empty(device, info->physical);
+
+       down_read(&dev_replace->rwsem);
+       dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
+       if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL)
+               btrfs_dev_clear_zone_empty(dev_replace->tgtdev, info->physical);
+       up_read(&dev_replace->rwsem);
+
+       /*
+        * The group is mapped to a sequential zone. Get the zone write pointer
+        * to determine the allocation offset within the zone.
+        */
+       WARN_ON(!IS_ALIGNED(info->physical, fs_info->zone_size));
+       nofs_flag = memalloc_nofs_save();
+       ret = btrfs_get_dev_zone(device, info->physical, &zone);
+       memalloc_nofs_restore(nofs_flag);
+       if (ret) {
+               if (ret != -EIO && ret != -EOPNOTSUPP)
+                       return ret;
+               info->alloc_offset = WP_MISSING_DEV;
+               return 0;
+       }
+
+       if (zone.type == BLK_ZONE_TYPE_CONVENTIONAL) {
+               btrfs_err_in_rcu(fs_info,
+               "zoned: unexpected conventional zone %llu on device %s (devid %llu)",
+                       zone.start << SECTOR_SHIFT, rcu_str_deref(device->name),
+                       device->devid);
+               return -EIO;
+       }
+
+       info->capacity = (zone.capacity << SECTOR_SHIFT);
+
+       switch (zone.cond) {
+       case BLK_ZONE_COND_OFFLINE:
+       case BLK_ZONE_COND_READONLY:
+               btrfs_err(fs_info,
+               "zoned: offline/readonly zone %llu on device %s (devid %llu)",
+                         (info->physical >> device->zone_info->zone_size_shift),
+                         rcu_str_deref(device->name), device->devid);
+               info->alloc_offset = WP_MISSING_DEV;
+               break;
+       case BLK_ZONE_COND_EMPTY:
+               info->alloc_offset = 0;
+               break;
+       case BLK_ZONE_COND_FULL:
+               info->alloc_offset = info->capacity;
+               break;
+       default:
+               /* Partially used zone. */
+               info->alloc_offset = ((zone.wp - zone.start) << SECTOR_SHIFT);
+               __set_bit(zone_idx, active);
+               break;
+       }
+
+       return 0;
+}
+
 int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
 {
        struct btrfs_fs_info *fs_info = cache->fs_info;
        struct extent_map_tree *em_tree = &fs_info->mapping_tree;
        struct extent_map *em;
        struct map_lookup *map;
-       struct btrfs_device *device;
        u64 logical = cache->start;
        u64 length = cache->length;
        struct zone_info *zone_info = NULL;
        int ret;
        int i;
-       unsigned int nofs_flag;
        unsigned long *active = NULL;
        u64 last_alloc = 0;
        u32 num_sequential = 0, num_conventional = 0;
@@ -1345,98 +1429,14 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
        }
 
        for (i = 0; i < map->num_stripes; i++) {
-               struct zone_info *info = &zone_info[i];
-               bool is_sequential;
-               struct blk_zone zone;
-               struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
-               int dev_replace_is_ongoing = 0;
-
-               device = map->stripes[i].dev;
-               info->physical = map->stripes[i].physical;
-
-               if (device->bdev == NULL) {
-                       info->alloc_offset = WP_MISSING_DEV;
-                       continue;
-               }
-
-               is_sequential = btrfs_dev_is_sequential(device, info->physical);
-               if (is_sequential)
-                       num_sequential++;
-               else
-                       num_conventional++;
-
-               /*
-                * Consider a zone as active if we can allow any number of
-                * active zones.
-                */
-               if (!device->zone_info->max_active_zones)
-                       __set_bit(i, active);
-
-               if (!is_sequential) {
-                       info->alloc_offset = WP_CONVENTIONAL;
-                       continue;
-               }
-
-               /*
-                * This zone will be used for allocation, so mark this zone
-                * non-empty.
-                */
-               btrfs_dev_clear_zone_empty(device, info->physical);
-
-               down_read(&dev_replace->rwsem);
-               dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
-               if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL)
-                       btrfs_dev_clear_zone_empty(dev_replace->tgtdev, info->physical);
-               up_read(&dev_replace->rwsem);
-
-               /*
-                * The group is mapped to a sequential zone. Get the zone write
-                * pointer to determine the allocation offset within the zone.
-                */
-               WARN_ON(!IS_ALIGNED(info->physical, fs_info->zone_size));
-               nofs_flag = memalloc_nofs_save();
-               ret = btrfs_get_dev_zone(device, info->physical, &zone);
-               memalloc_nofs_restore(nofs_flag);
-               if (ret == -EIO || ret == -EOPNOTSUPP) {
-                       ret = 0;
-                       info->alloc_offset = WP_MISSING_DEV;
-                       continue;
-               } else if (ret) {
-                       goto out;
-               }
-
-               if (zone.type == BLK_ZONE_TYPE_CONVENTIONAL) {
-                       btrfs_err_in_rcu(fs_info,
-       "zoned: unexpected conventional zone %llu on device %s (devid %llu)",
-                               zone.start << SECTOR_SHIFT,
-                               rcu_str_deref(device->name), device->devid);
-                       ret = -EIO;
+               ret = btrfs_load_zone_info(fs_info, i, &zone_info[i], active, map);
+               if (ret)
                        goto out;
-               }
-
-               info->capacity = (zone.capacity << SECTOR_SHIFT);
 
-               switch (zone.cond) {
-               case BLK_ZONE_COND_OFFLINE:
-               case BLK_ZONE_COND_READONLY:
-                       btrfs_err(fs_info,
-               "zoned: offline/readonly zone %llu on device %s (devid %llu)",
-                                 info->physical >> device->zone_info->zone_size_shift,
-                                 rcu_str_deref(device->name), device->devid);
-                       info->alloc_offset = WP_MISSING_DEV;
-                       break;
-               case BLK_ZONE_COND_EMPTY:
-                       info->alloc_offset = 0;
-                       break;
-               case BLK_ZONE_COND_FULL:
-                       info->alloc_offset = info->capacity;
-                       break;
-               default:
-                       /* Partially used zone */
-                       info->alloc_offset = ((zone.wp - zone.start) << SECTOR_SHIFT);
-                       __set_bit(i, active);
-                       break;
-               }
+               if (zone_info[i].alloc_offset == WP_CONVENTIONAL)
+                       num_conventional++;
+               else
+                       num_sequential++;
        }
 
        if (num_sequential > 0)