[PATCH v2 10/11] block: Add support for the zone capacity concept

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Make the zone capacity available in struct queue_limits for those
drivers that need it.

Cc: Damien Le Moal <damien.lemoal@xxxxxxxxxxxxxxxxxx>
Cc: Christoph Hellwig <hch@xxxxxx>
Cc: Ming Lei <ming.lei@xxxxxxxxxx>
Signed-off-by: Bart Van Assche <bvanassche@xxxxxxx>
---
 Documentation/ABI/stable/sysfs-block |  8 ++++++++
 block/blk-settings.c                 |  1 +
 block/blk-sysfs.c                    |  7 +++++++
 block/blk-zoned.c                    | 15 +++++++++++++++
 include/linux/blkdev.h               |  1 +
 5 files changed, 32 insertions(+)

diff --git a/Documentation/ABI/stable/sysfs-block b/Documentation/ABI/stable/sysfs-block
index c57e5b7cb532..4527d0514fdb 100644
--- a/Documentation/ABI/stable/sysfs-block
+++ b/Documentation/ABI/stable/sysfs-block
@@ -671,6 +671,14 @@ Description:
 		regular block devices.
 
 
+What:		/sys/block/<disk>/queue/zone_capacity
+Date:		March 2023
+Contact:	linux-block@xxxxxxxxxxxxxxx
+Description:
+		[RO] The number of 512-byte sectors in a zone that can be read
+		or written. This number is less than or equal to the zone size.
+
+
 What:		/sys/block/<disk>/queue/zone_write_granularity
 Date:		January 2021
 Contact:	linux-block@xxxxxxxxxxxxxxx
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 896b4654ab00..96f5dc63a815 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -685,6 +685,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
 						   b->max_secure_erase_sectors);
 	t->zone_write_granularity = max(t->zone_write_granularity,
 					b->zone_write_granularity);
+	t->zone_capacity = max(t->zone_capacity, b->zone_capacity);
 	t->zoned = max(t->zoned, b->zoned);
 	return ret;
 }
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index a64208583853..0443b8f536f4 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -337,6 +337,11 @@ static ssize_t queue_nr_zones_show(struct request_queue *q, char *page)
 	return queue_var_show(disk_nr_zones(q->disk), page);
 }
 
+static ssize_t queue_zone_capacity_show(struct request_queue *q, char *page)
+{
+	return queue_var_show(q->limits.zone_capacity, page);
+}
+
 static ssize_t queue_max_open_zones_show(struct request_queue *q, char *page)
 {
 	return queue_var_show(bdev_max_open_zones(q->disk->part0), page);
@@ -587,6 +592,7 @@ QUEUE_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");
 
 QUEUE_RO_ENTRY(queue_zoned, "zoned");
 QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
+QUEUE_RO_ENTRY(queue_zone_capacity, "zone_capacity");
 QUEUE_RO_ENTRY(queue_max_open_zones, "max_open_zones");
 QUEUE_RO_ENTRY(queue_max_active_zones, "max_active_zones");
 
@@ -644,6 +650,7 @@ static struct attribute *queue_attrs[] = {
 	&queue_nonrot_entry.attr,
 	&queue_zoned_entry.attr,
 	&queue_nr_zones_entry.attr,
+	&queue_zone_capacity_entry.attr,
 	&queue_max_open_zones_entry.attr,
 	&queue_max_active_zones_entry.attr,
 	&queue_nomerges_entry.attr,
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index 9b9cd6adfd1b..a319acbe377b 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -463,6 +463,7 @@ struct blk_revalidate_zone_args {
 	unsigned long	*seq_zones_wlock;
 	unsigned int	nr_zones;
 	sector_t	zone_sectors;
+	sector_t	zone_capacity;
 	sector_t	sector;
 };
 
@@ -489,6 +490,7 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
 		}
 
 		args->zone_sectors = zone->len;
+		args->zone_capacity = zone->capacity;
 		args->nr_zones = (capacity + zone->len - 1) >> ilog2(zone->len);
 	} else if (zone->start + args->zone_sectors < capacity) {
 		if (zone->len != args->zone_sectors) {
@@ -496,12 +498,23 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
 				disk->disk_name);
 			return -ENODEV;
 		}
+		if (zone->capacity != args->zone_capacity) {
+			pr_warn("%s: Invalid zoned device with non constant zone capacity\n",
+				disk->disk_name);
+			return -ENODEV;
+		}
 	} else {
 		if (zone->len > args->zone_sectors) {
 			pr_warn("%s: Invalid zoned device with larger last zone size\n",
 				disk->disk_name);
 			return -ENODEV;
 		}
+		if (zone->capacity >
+		    min(args->zone_sectors, args->zone_capacity)) {
+			pr_warn("%s: Invalid zoned device with too large last zone capacity\n",
+				disk->disk_name);
+			return -ENODEV;
+		}
 	}
 
 	/* Check for holes in the zone report */
@@ -604,6 +617,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
 	blk_mq_freeze_queue(q);
 	if (ret > 0) {
 		blk_queue_chunk_sectors(q, args.zone_sectors);
+		q->limits.zone_capacity = args.zone_capacity;
 		disk->nr_zones = args.nr_zones;
 		swap(disk->seq_zones_wlock, args.seq_zones_wlock);
 		swap(disk->conv_zones_bitmap, args.conv_zones_bitmap);
@@ -635,6 +649,7 @@ void disk_clear_zone_settings(struct gendisk *disk)
 	disk->max_open_zones = 0;
 	disk->max_active_zones = 0;
 	q->limits.chunk_sectors = 0;
+	q->limits.zone_capacity = 0;
 	q->limits.zone_write_granularity = 0;
 	q->limits.max_zone_append_sectors = 0;
 
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 261538319bbf..4fb0e6d7fdc8 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -297,6 +297,7 @@ struct queue_limits {
 	unsigned int		discard_granularity;
 	unsigned int		discard_alignment;
 	unsigned int		zone_write_granularity;
+	unsigned int		zone_capacity;
 
 	unsigned short		max_segments;
 	unsigned short		max_integrity_segments;



[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux