btrfs: zoned: skip ZONE FINISH of conventional zones
authorJohannes Thumshirn <johannes.thumshirn@wdc.com>
Wed, 23 Jul 2025 13:38:10 +0000 (15:38 +0200)
committerDavid Sterba <dsterba@suse.com>
Wed, 13 Aug 2025 10:28:42 +0000 (12:28 +0200)
Don't call ZONE FINISH for conventional zones as this will result in I/O
errors. Instead check if the zone that needs finishing is a conventional
zone and if yes skip it.

Also factor out the actual handling of finishing a single zone into a
helper function, as do_zone_finish() is growing ever bigger and the
indentations levels are getting higher.

Reviewed-by: Naohiro Aota <naohiro.aota@wdc.com>
Reviewed-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/zoned.c

index db11b5b5f0e66939363200bf7f6ffcae43deb74c..36de6d0d595f8097b0e2339f7de155d6f7de736a 100644 (file)
@@ -2245,6 +2245,40 @@ static void wait_eb_writebacks(struct btrfs_block_group *block_group)
        rcu_read_unlock();
 }
 
+static int call_zone_finish(struct btrfs_block_group *block_group,
+                           struct btrfs_io_stripe *stripe)
+{
+       struct btrfs_device *device = stripe->dev;
+       const u64 physical = stripe->physical;
+       struct btrfs_zoned_device_info *zinfo = device->zone_info;
+       int ret;
+
+       if (!device->bdev)
+               return 0;
+
+       if (zinfo->max_active_zones == 0)
+               return 0;
+
+       if (btrfs_dev_is_sequential(device, physical)) {
+               unsigned int nofs_flags;
+
+               nofs_flags = memalloc_nofs_save();
+               ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
+                                      physical >> SECTOR_SHIFT,
+                                      zinfo->zone_size >> SECTOR_SHIFT);
+               memalloc_nofs_restore(nofs_flags);
+
+               if (ret)
+                       return ret;
+       }
+
+       if (!(block_group->flags & BTRFS_BLOCK_GROUP_DATA))
+               zinfo->reserved_active_zones++;
+       btrfs_dev_clear_active_zone(device, physical);
+
+       return 0;
+}
+
 static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_written)
 {
        struct btrfs_fs_info *fs_info = block_group->fs_info;
@@ -2329,31 +2363,12 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
        down_read(&dev_replace->rwsem);
        map = block_group->physical_map;
        for (i = 0; i < map->num_stripes; i++) {
-               struct btrfs_device *device = map->stripes[i].dev;
-               const u64 physical = map->stripes[i].physical;
-               struct btrfs_zoned_device_info *zinfo = device->zone_info;
-               unsigned int nofs_flags;
-
-               if (!device->bdev)
-                       continue;
-
-               if (zinfo->max_active_zones == 0)
-                       continue;
-
-               nofs_flags = memalloc_nofs_save();
-               ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
-                                      physical >> SECTOR_SHIFT,
-                                      zinfo->zone_size >> SECTOR_SHIFT);
-               memalloc_nofs_restore(nofs_flags);
 
+               ret = call_zone_finish(block_group, &map->stripes[i]);
                if (ret) {
                        up_read(&dev_replace->rwsem);
                        return ret;
                }
-
-               if (!(block_group->flags & BTRFS_BLOCK_GROUP_DATA))
-                       zinfo->reserved_active_zones++;
-               btrfs_dev_clear_active_zone(device, physical);
        }
        up_read(&dev_replace->rwsem);