Skip to content

Commit ea6f8dd

Browse files
naotakdave
authored andcommitted
btrfs: zoned: load active zone information from devices
The ZNS specification defines a limit on the number of zones that can be in the implicit open, explicit open or closed conditions. Any zone with such condition is defined as an active zone and correspond to any zone that is being written or that has been only partially written. If the maximum number of active zones is reached, we must either reset or finish some active zones before being able to chose other zones for storing data. Load queue_max_active_zones() and track the number of active zones left on the device. Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 8376d9e commit ea6f8dd

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

fs/btrfs/zoned.c

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <linux/slab.h>
55
#include <linux/blkdev.h>
66
#include <linux/sched/mm.h>
7+
#include <linux/atomic.h>
78
#include "ctree.h"
89
#include "volumes.h"
910
#include "zoned.h"
@@ -38,6 +39,16 @@
3839
/* Number of superblock log zones */
3940
#define BTRFS_NR_SB_LOG_ZONES 2
4041

42+
/*
43+
* Minimum of active zones we need:
44+
*
45+
* - BTRFS_SUPER_MIRROR_MAX zones for superblock mirrors
46+
* - 3 zones to ensure at least one zone per SYSTEM, META and DATA block group
47+
* - 1 zone for tree-log dedicated block group
48+
* - 1 zone for relocation
49+
*/
50+
#define BTRFS_MIN_ACTIVE_ZONES (BTRFS_SUPER_MIRROR_MAX + 5)
51+
4152
/*
4253
* Maximum supported zone size. Currently, SMR disks have a zone size of
4354
* 256MiB, and we are expecting ZNS drives to be in the 1-4GiB range. We do not
@@ -303,6 +314,9 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device)
303314
struct btrfs_fs_info *fs_info = device->fs_info;
304315
struct btrfs_zoned_device_info *zone_info = NULL;
305316
struct block_device *bdev = device->bdev;
317+
struct request_queue *queue = bdev_get_queue(bdev);
318+
unsigned int max_active_zones;
319+
unsigned int nactive;
306320
sector_t nr_sectors;
307321
sector_t sector = 0;
308322
struct blk_zone *zones = NULL;
@@ -358,6 +372,17 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device)
358372
if (!IS_ALIGNED(nr_sectors, zone_sectors))
359373
zone_info->nr_zones++;
360374

375+
max_active_zones = queue_max_active_zones(queue);
376+
if (max_active_zones && max_active_zones < BTRFS_MIN_ACTIVE_ZONES) {
377+
btrfs_err_in_rcu(fs_info,
378+
"zoned: %s: max active zones %u is too small, need at least %u active zones",
379+
rcu_str_deref(device->name), max_active_zones,
380+
BTRFS_MIN_ACTIVE_ZONES);
381+
ret = -EINVAL;
382+
goto out;
383+
}
384+
zone_info->max_active_zones = max_active_zones;
385+
361386
zone_info->seq_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL);
362387
if (!zone_info->seq_zones) {
363388
ret = -ENOMEM;
@@ -370,13 +395,20 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device)
370395
goto out;
371396
}
372397

398+
zone_info->active_zones = bitmap_zalloc(zone_info->nr_zones, GFP_KERNEL);
399+
if (!zone_info->active_zones) {
400+
ret = -ENOMEM;
401+
goto out;
402+
}
403+
373404
zones = kcalloc(BTRFS_REPORT_NR_ZONES, sizeof(struct blk_zone), GFP_KERNEL);
374405
if (!zones) {
375406
ret = -ENOMEM;
376407
goto out;
377408
}
378409

379410
/* Get zones type */
411+
nactive = 0;
380412
while (sector < nr_sectors) {
381413
nr_zones = BTRFS_REPORT_NR_ZONES;
382414
ret = btrfs_get_dev_zones(device, sector << SECTOR_SHIFT, zones,
@@ -387,8 +419,17 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device)
387419
for (i = 0; i < nr_zones; i++) {
388420
if (zones[i].type == BLK_ZONE_TYPE_SEQWRITE_REQ)
389421
__set_bit(nreported, zone_info->seq_zones);
390-
if (zones[i].cond == BLK_ZONE_COND_EMPTY)
422+
switch (zones[i].cond) {
423+
case BLK_ZONE_COND_EMPTY:
391424
__set_bit(nreported, zone_info->empty_zones);
425+
break;
426+
case BLK_ZONE_COND_IMP_OPEN:
427+
case BLK_ZONE_COND_EXP_OPEN:
428+
case BLK_ZONE_COND_CLOSED:
429+
__set_bit(nreported, zone_info->active_zones);
430+
nactive++;
431+
break;
432+
}
392433
nreported++;
393434
}
394435
sector = zones[nr_zones - 1].start + zones[nr_zones - 1].len;
@@ -403,6 +444,19 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device)
403444
goto out;
404445
}
405446

447+
if (max_active_zones) {
448+
if (nactive > max_active_zones) {
449+
btrfs_err_in_rcu(device->fs_info,
450+
"zoned: %u active zones on %s exceeds max_active_zones %u",
451+
nactive, rcu_str_deref(device->name),
452+
max_active_zones);
453+
ret = -EIO;
454+
goto out;
455+
}
456+
atomic_set(&zone_info->active_zones_left,
457+
max_active_zones - nactive);
458+
}
459+
406460
/* Validate superblock log */
407461
nr_zones = BTRFS_NR_SB_LOG_ZONES;
408462
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
@@ -485,6 +539,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device)
485539
out:
486540
kfree(zones);
487541
out_free_zone_info:
542+
bitmap_free(zone_info->active_zones);
488543
bitmap_free(zone_info->empty_zones);
489544
bitmap_free(zone_info->seq_zones);
490545
kfree(zone_info);
@@ -500,6 +555,7 @@ void btrfs_destroy_dev_zone_info(struct btrfs_device *device)
500555
if (!zone_info)
501556
return;
502557

558+
bitmap_free(zone_info->active_zones);
503559
bitmap_free(zone_info->seq_zones);
504560
bitmap_free(zone_info->empty_zones);
505561
kfree(zone_info);

fs/btrfs/zoned.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ struct btrfs_zoned_device_info {
2323
u64 zone_size;
2424
u8 zone_size_shift;
2525
u32 nr_zones;
26+
unsigned int max_active_zones;
27+
atomic_t active_zones_left;
2628
unsigned long *seq_zones;
2729
unsigned long *empty_zones;
30+
unsigned long *active_zones;
2831
struct blk_zone sb_zones[2 * BTRFS_SUPER_MIRROR_MAX];
2932
};
3033

0 commit comments

Comments
 (0)