block: Enhance blk_revalidate_disk_zones()
[sfrench/cifs-2.6.git] / drivers / scsi / sd_zbc.c
index 39f10ec0dfcfdd21eeb77c8f30266505f87bce07..7c4690f2669831eb416e1ccda296e4296f379688 100644 (file)
@@ -339,32 +339,19 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
  * 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 */
@@ -379,82 +366,28 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks)
                }
        }
 
-       /*
-        * 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)
@@ -480,7 +413,7 @@ 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;