summaryrefslogtreecommitdiffstats
path: root/block/blk-zoned.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/blk-zoned.c')
-rw-r--r--block/blk-zoned.c62
1 files changed, 60 insertions, 2 deletions
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index 481eaf7d04d4..dae787f67019 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -448,6 +448,58 @@ void blk_queue_free_zone_bitmaps(struct request_queue *q)
q->seq_zones_wlock = NULL;
}
+/*
+ * Helper function to check the validity of zones of a zoned block device.
+ */
+static bool blk_zone_valid(struct gendisk *disk, struct blk_zone *zone,
+ sector_t *sector)
+{
+ struct request_queue *q = disk->queue;
+ sector_t zone_sectors = blk_queue_zone_sectors(q);
+ sector_t capacity = get_capacity(disk);
+
+ /*
+ * All zones must have the same size, with the exception on an eventual
+ * smaller last zone.
+ */
+ if (zone->start + zone_sectors < capacity &&
+ zone->len != zone_sectors) {
+ pr_warn("%s: Invalid zoned device with non constant zone size\n",
+ disk->disk_name);
+ return false;
+ }
+
+ if (zone->start + zone->len >= capacity &&
+ zone->len > zone_sectors) {
+ pr_warn("%s: Invalid zoned device with larger last zone size\n",
+ disk->disk_name);
+ return false;
+ }
+
+ /* Check for holes in the zone report */
+ if (zone->start != *sector) {
+ pr_warn("%s: Zone gap at sectors %llu..%llu\n",
+ disk->disk_name, *sector, zone->start);
+ return false;
+ }
+
+ /* Check zone type */
+ switch (zone->type) {
+ case BLK_ZONE_TYPE_CONVENTIONAL:
+ case BLK_ZONE_TYPE_SEQWRITE_REQ:
+ case BLK_ZONE_TYPE_SEQWRITE_PREF:
+ break;
+ default:
+ pr_warn("%s: Invalid zone type 0x%x at sectors %llu\n",
+ disk->disk_name, (int)zone->type, zone->start);
+ return false;
+ }
+
+ *sector += zone->len;
+
+ return true;
+}
+
/**
* blk_revalidate_disk_zones - (re)allocate and initialize zone bitmaps
* @disk: Target disk
@@ -497,7 +549,10 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
if (!seq_zones_bitmap)
goto out;
- /* Get zone information and initialize seq_zones_bitmap */
+ /*
+ * Get zone information to check the zones and initialize
+ * seq_zones_bitmap.
+ */
rep_nr_zones = nr_zones;
zones = blk_alloc_zones(&rep_nr_zones);
if (!zones)
@@ -511,11 +566,14 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
if (!nrz)
break;
for (i = 0; i < nrz; i++) {
+ if (!blk_zone_valid(disk, &zones[i], &sector)) {
+ ret = -ENODEV;
+ goto out;
+ }
if (zones[i].type != BLK_ZONE_TYPE_CONVENTIONAL)
set_bit(z, seq_zones_bitmap);
z++;
}
- sector += nrz * blk_queue_zone_sectors(q);
}
if (WARN_ON(z != nr_zones)) {