Commit ecfe43b1 authored by Damien Le Moal's avatar Damien Le Moal Committed by Jens Axboe

block: Remember zone capacity when revalidating zones

In preparation for adding zone write plugging, modify
blk_revalidate_disk_zones() to get the capacity of zones of a zoned
block device. This capacity value as a number of 512B sectors is stored
in the gendisk zone_capacity field.

Given that host-managed SMR disks (including zoned UFS drives) and all
known NVMe ZNS devices have the same zone capacity for all zones
blk_revalidate_disk_zones() returns an error if different capacities are
detected for different zones.

This also adds check to verify that the values reported by the device
for zone capacities are correct, that is, that the zone capacity is
never 0, does not exceed the zone size and is equal to the zone size for
conventional zones.
Signed-off-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarBart Van Assche <bvanassche@acm.org>
Tested-by: default avatarHans Holmberg <hans.holmberg@wdc.com>
Tested-by: default avatarDennis Maisenbacher <dennis.maisenbacher@wdc.com>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Link: https://lore.kernel.org/r/20240408014128.205141-7-dlemoal@kernel.orgSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent dd850ff3
...@@ -438,6 +438,7 @@ struct blk_revalidate_zone_args { ...@@ -438,6 +438,7 @@ struct blk_revalidate_zone_args {
unsigned long *conv_zones_bitmap; unsigned long *conv_zones_bitmap;
unsigned long *seq_zones_wlock; unsigned long *seq_zones_wlock;
unsigned int nr_zones; unsigned int nr_zones;
unsigned int zone_capacity;
sector_t sector; sector_t sector;
}; };
...@@ -482,9 +483,20 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx, ...@@ -482,9 +483,20 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
return -ENODEV; return -ENODEV;
} }
if (!zone->capacity || zone->capacity > zone->len) {
pr_warn("%s: Invalid zone capacity\n",
disk->disk_name);
return -ENODEV;
}
/* Check zone type */ /* Check zone type */
switch (zone->type) { switch (zone->type) {
case BLK_ZONE_TYPE_CONVENTIONAL: case BLK_ZONE_TYPE_CONVENTIONAL:
if (zone->capacity != zone->len) {
pr_warn("%s: Invalid conventional zone capacity\n",
disk->disk_name);
return -ENODEV;
}
if (!args->conv_zones_bitmap) { if (!args->conv_zones_bitmap) {
args->conv_zones_bitmap = args->conv_zones_bitmap =
blk_alloc_zone_bitmap(q->node, args->nr_zones); blk_alloc_zone_bitmap(q->node, args->nr_zones);
...@@ -500,6 +512,18 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx, ...@@ -500,6 +512,18 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
if (!args->seq_zones_wlock) if (!args->seq_zones_wlock)
return -ENOMEM; return -ENOMEM;
} }
/*
* Remember the capacity of the first sequential zone and check
* if it is constant for all zones.
*/
if (!args->zone_capacity)
args->zone_capacity = zone->capacity;
if (zone->capacity != args->zone_capacity) {
pr_warn("%s: Invalid variable zone capacity\n",
disk->disk_name);
return -ENODEV;
}
break; break;
case BLK_ZONE_TYPE_SEQWRITE_PREF: case BLK_ZONE_TYPE_SEQWRITE_PREF:
default: default:
...@@ -595,6 +619,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk, ...@@ -595,6 +619,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
blk_mq_freeze_queue(q); blk_mq_freeze_queue(q);
if (ret > 0) { if (ret > 0) {
disk->nr_zones = args.nr_zones; disk->nr_zones = args.nr_zones;
disk->zone_capacity = args.zone_capacity;
swap(disk->seq_zones_wlock, args.seq_zones_wlock); swap(disk->seq_zones_wlock, args.seq_zones_wlock);
swap(disk->conv_zones_bitmap, args.conv_zones_bitmap); swap(disk->conv_zones_bitmap, args.conv_zones_bitmap);
if (update_driver_data) if (update_driver_data)
...@@ -608,6 +633,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk, ...@@ -608,6 +633,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
kfree(args.seq_zones_wlock); kfree(args.seq_zones_wlock);
kfree(args.conv_zones_bitmap); kfree(args.conv_zones_bitmap);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones); EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones);
...@@ -191,6 +191,7 @@ struct gendisk { ...@@ -191,6 +191,7 @@ struct gendisk {
* blk_mq_unfreeze_queue(). * blk_mq_unfreeze_queue().
*/ */
unsigned int nr_zones; unsigned int nr_zones;
unsigned int zone_capacity;
unsigned long *conv_zones_bitmap; unsigned long *conv_zones_bitmap;
unsigned long *seq_zones_wlock; unsigned long *seq_zones_wlock;
#endif /* CONFIG_BLK_DEV_ZONED */ #endif /* CONFIG_BLK_DEV_ZONED */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment