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
        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)
                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)) {
 
  * Returns the zone size in number of blocks upon success or an error code
  * upon failure.
  */
-static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks)
+static int sd_zbc_check_zones(struct scsi_disk *sdkp, unsigned char *buf,
+                             u32 *zblocks)
 {
-       size_t bufsize, buflen;
-       unsigned int noio_flag;
+       size_t buflen;
        u64 zone_blocks = 0;
-       sector_t max_lba, block = 0;
-       unsigned char *buf;
+       sector_t max_lba;
        unsigned char *rec;
        int ret;
-       u8 same;
-
-       /* Do all memory allocations as if GFP_NOIO was specified */
-       noio_flag = memalloc_noio_save();
 
-       /* Get a buffer */
-       buf = sd_zbc_alloc_report_buffer(sdkp, SD_ZBC_REPORT_MAX_ZONES,
-                                        &bufsize);
-       if (!buf) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       /* Do a report zone to get max_lba and the same field */
-       ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, 0, false);
+       /* Do a report zone to get max_lba and the size of the first zone */
+       ret = sd_zbc_do_report_zones(sdkp, buf, SD_BUF_SIZE, 0, false);
        if (ret)
-               goto out_free;
+               return ret;
 
        if (sdkp->rc_basis == 0) {
                /* The max_lba field is the capacity of this device */
                }
        }
 
-       /*
-        * Check same field: for any value other than 0, we know that all zones
-        * have the same size.
-        */
-       same = buf[4] & 0x0f;
-       if (same > 0) {
-               rec = &buf[64];
-               zone_blocks = get_unaligned_be64(&rec[8]);
-               goto out;
-       }
-
-       /*
-        * Check the size of all zones: all zones must be of
-        * equal size, except the last zone which can be smaller
-        * than other zones.
-        */
-       do {
-
-               /* Parse REPORT ZONES header */
-               buflen = min_t(size_t, get_unaligned_be32(&buf[0]) + 64,
-                              bufsize);
-               rec = buf + 64;
-
-               /* Parse zone descriptors */
-               while (rec < buf + buflen) {
-                       u64 this_zone_blocks = get_unaligned_be64(&rec[8]);
-
-                       if (zone_blocks == 0) {
-                               zone_blocks = this_zone_blocks;
-                       } else if (this_zone_blocks != zone_blocks &&
-                                  (block + this_zone_blocks < sdkp->capacity
-                                   || this_zone_blocks > zone_blocks)) {
-                               zone_blocks = 0;
-                               goto out;
-                       }
-                       block += this_zone_blocks;
-                       rec += 64;
-               }
-
-               if (block < sdkp->capacity) {
-                       ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, block,
-                                                    true);
-                       if (ret)
-                               goto out_free;
-               }
-
-       } while (block < sdkp->capacity);
-
-out:
-       if (!zone_blocks) {
-               if (sdkp->first_scan)
-                       sd_printk(KERN_NOTICE, sdkp,
-                                 "Devices with non constant zone "
-                                 "size are not supported\n");
-               ret = -ENODEV;
-       } else if (!is_power_of_2(zone_blocks)) {
+       /* Parse REPORT ZONES header */
+       buflen = min_t(size_t, get_unaligned_be32(&buf[0]) + 64, SD_BUF_SIZE);
+       rec = buf + 64;
+       zone_blocks = get_unaligned_be64(&rec[8]);
+       if (!zone_blocks || !is_power_of_2(zone_blocks)) {
                if (sdkp->first_scan)
                        sd_printk(KERN_NOTICE, sdkp,
                                  "Devices with non power of 2 zone "
                                  "size are not supported\n");
-               ret = -ENODEV;
-       } else if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) {
+               return -ENODEV;
+       }
+
+       if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) {
                if (sdkp->first_scan)
                        sd_printk(KERN_NOTICE, sdkp,
                                  "Zone size too large\n");
-               ret = -EFBIG;
-       } else {
-               *zblocks = zone_blocks;
-               ret = 0;
+               return -EFBIG;
        }
 
-out_free:
-       memalloc_noio_restore(noio_flag);
-       kvfree(buf);
+       *zblocks = zone_blocks;
 
-       return ret;
+       return 0;
 }
 
 int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
         * Check zone size: only devices with a constant zone size (except
         * an eventual last runt zone) that is a power of 2 are supported.
         */
-       ret = sd_zbc_check_zones(sdkp, &zone_blocks);
+       ret = sd_zbc_check_zones(sdkp, buf, &zone_blocks);
        if (ret != 0)
                goto err;