diff options
Diffstat (limited to 'block/blk-zoned.c')
-rw-r--r-- | block/blk-zoned.c | 62 |
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], §or)) { + 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)) { |