diff mbox series

[1/6] null_blk: Fix zone size initialization

Message ID 20201109125105.551734-2-damien.lemoal@wdc.com (mailing list archive)
State New, archived
Headers show
Series [1/6] null_blk: Fix zone size initialization | expand

Commit Message

Damien Le Moal Nov. 9, 2020, 12:51 p.m. UTC
All zones of a zoned null_blk device are currently initialized with the
same size. However, if the specified size (capacity) of the null_blk
device is not a multiple of the zone size, the last zone becomes too
large and read/write accesses to it can cause out of bound errors.
Fix this by correctly setting the size of the last zone of the device
to the remainder of the disk capacity if this capacity is not a
multiple of the zone size. For such smaller last zone, the zone
capacity is also checked so that it does not exceed the smaller zone
size.

Reported-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 drivers/block/null_blk_zoned.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/drivers/block/null_blk_zoned.c b/drivers/block/null_blk_zoned.c
index beb34b4f76b0..18911e67f792 100644
--- a/drivers/block/null_blk_zoned.c
+++ b/drivers/block/null_blk_zoned.c
@@ -16,7 +16,7 @@  static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
 
 int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
 {
-	sector_t dev_size = (sector_t)dev->size * 1024 * 1024;
+	sector_t dev_capacity, zone_capacity;
 	sector_t sector = 0;
 	unsigned int i;
 
@@ -38,9 +38,14 @@  int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
 		return -EINVAL;
 	}
 
+	zone_capacity = dev->zone_capacity << ZONE_SIZE_SHIFT;
+	dev_capacity = ((sector_t)dev->size * SZ_1M) >> SECTOR_SHIFT;
+
 	dev->zone_size_sects = dev->zone_size << ZONE_SIZE_SHIFT;
-	dev->nr_zones = dev_size >>
-				(SECTOR_SHIFT + ilog2(dev->zone_size_sects));
+	dev->nr_zones = dev_capacity >> ilog2(dev->zone_size_sects);
+	if (dev_capacity & (dev->zone_size_sects - 1))
+		dev->nr_zones++;
+
 	dev->zones = kvmalloc_array(dev->nr_zones, sizeof(struct blk_zone),
 			GFP_KERNEL | __GFP_ZERO);
 	if (!dev->zones)
@@ -101,8 +106,12 @@  int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
 		struct blk_zone *zone = &dev->zones[i];
 
 		zone->start = zone->wp = sector;
-		zone->len = dev->zone_size_sects;
-		zone->capacity = dev->zone_capacity << ZONE_SIZE_SHIFT;
+		if (zone->start + dev->zone_size_sects > dev_capacity)
+			zone->len = dev_capacity - zone->start;
+		else
+			zone->len = dev->zone_size_sects;
+		zone->capacity =
+			min_t(sector_t, zone->len, zone_capacity);
 		zone->type = BLK_ZONE_TYPE_SEQWRITE_REQ;
 		zone->cond = BLK_ZONE_COND_EMPTY;