btrfs: zoned: always set max_active_zones for zoned devices

When a block device does not report a maximum number of open or active
zones,  currently assign BTRFS_DEFAULT_MAX_ACTIVE_ZONES (128) to
the internal limit, if the device has more than
BTRFS_DEFAULT_MAX_ACTIVE_ZONES zones.

But if the device has less than BTRFS_DEFAULT_MAX_ACTIVE_ZONES the
internal max_active_zones limit will stay at 0, even if the device has
zone resource limits. Furthermore, if the device has a total number of
zones that is less than BTRFS_DEFAULT_MAX_ACTIVE_ZONE, max_active_zones
should be set to at most the number of zones.

Also move the max_active_zone calculation and setting into a dedicated
helper, to shrink btrfs_get_dev_zone_info().

Fixes: 04147d8394 ("btrfs: zoned: limit active zones to max_open_zones")
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Johannes Thumshirn 2026-05-22 11:22:12 +02:00
parent 3f1cc3620e
commit 21a3533b99

View File

@ -356,12 +356,33 @@ int btrfs_get_dev_zone_info_all_devices(struct btrfs_fs_info *fs_info)
return ret;
}
static int btrfs_get_max_active_zones(struct btrfs_device *device,
struct btrfs_zoned_device_info *zone_info)
{
struct block_device *bdev = device->bdev;
int max_active_zones;
if (unlikely(zone_info->nr_zones < BTRFS_MIN_ACTIVE_ZONES)) {
btrfs_err(device->fs_info, "zoned: not enough zones to mount filesystem: %u < %d",
zone_info->nr_zones, BTRFS_MIN_ACTIVE_ZONES);
return -EINVAL;
}
max_active_zones = min_not_zero(bdev_max_active_zones(bdev),
bdev_max_open_zones(bdev));
if (max_active_zones == 0)
max_active_zones = min(zone_info->nr_zones / 4,
BTRFS_DEFAULT_MAX_ACTIVE_ZONES);
zone_info->max_active_zones = max(max_active_zones, BTRFS_MIN_ACTIVE_ZONES);
return 0;
}
int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
{
struct btrfs_fs_info *fs_info = device->fs_info;
struct btrfs_zoned_device_info *zone_info = NULL;
struct block_device *bdev = device->bdev;
unsigned int max_active_zones;
unsigned int nactive;
sector_t nr_sectors;
sector_t sector = 0;
@ -426,19 +447,9 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
if (!IS_ALIGNED(nr_sectors, zone_sectors))
zone_info->nr_zones++;
max_active_zones = min_not_zero(bdev_max_active_zones(bdev),
bdev_max_open_zones(bdev));
if (!max_active_zones && zone_info->nr_zones > BTRFS_DEFAULT_MAX_ACTIVE_ZONES)
max_active_zones = BTRFS_DEFAULT_MAX_ACTIVE_ZONES;
if (max_active_zones && max_active_zones < BTRFS_MIN_ACTIVE_ZONES) {
btrfs_err(fs_info,
"zoned: %s: max active zones %u is too small, need at least %u active zones",
rcu_dereference(device->name), max_active_zones,
BTRFS_MIN_ACTIVE_ZONES);
ret = -EINVAL;
ret = btrfs_get_max_active_zones(device, zone_info);
if (ret)
goto out;
}
zone_info->max_active_zones = max_active_zones;
zone_info->seq_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL);
if (!zone_info->seq_zones) {
@ -519,26 +530,29 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
goto out;
}
if (max_active_zones) {
if (unlikely(nactive > max_active_zones)) {
if (bdev_max_active_zones(bdev) == 0) {
max_active_zones = 0;
zone_info->max_active_zones = 0;
goto validate;
}
if (unlikely(nactive > zone_info->max_active_zones)) {
if (bdev_max_active_zones(bdev) > 0) {
btrfs_err(device->fs_info,
"zoned: %u active zones on %s exceeds max_active_zones %u",
nactive, rcu_dereference(device->name),
max_active_zones);
"zoned: %u active zones on %s exceeds max_active_zones %u",
nactive, rcu_dereference(device->name),
zone_info->max_active_zones);
ret = -EIO;
goto out;
}
/*
* This is for backward compatibility with old filesystems that
* have a lot of active zones because the device doesn't report
* a maximum number of zones and we previously didn't care for
* the limit.
*/
zone_info->max_active_zones = 0;
} else {
atomic_set(&zone_info->active_zones_left,
max_active_zones - nactive);
zone_info->max_active_zones - nactive);
set_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &fs_info->flags);
}
validate:
/* Validate superblock log */
nr_zones = BTRFS_NR_SB_LOG_ZONES;
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {