Skip to content

Commit d2e428e

Browse files
damien-lemoalaxboe
authored andcommitted
scsi: sd_zbc: Reduce boot device scan and revalidate time
Handling checks of ZBC device capacity using the max_lba field of the REPORT ZONES command reply for disks with rc_basis == 0 can be done using the same report zones command reply used to check the "same" field. Avoid executing a report zones command solely to check the disk capacity by merging sd_zbc_check_capacity() into sd_zbc_check_zone_size() and renaming that function to sd_zbc_check_zones(). This removes a costly execution of a full report zones command and so reduces device scan duration at boot time as well as the duration of disk revalidate calls. Furthermore, setting the partial report bit in the REPORT ZONES command cdb can significantly reduce this command execution time as the device does not have to count and report the total number of zones that could be reported assuming a large enough reply buffer. A non-partial zone report is necessary only for the first execution of report zones used to check the same field value (to ensure that this value applies to all zones of the disk). All other calls to sd_zbc_report_zones() can use a partial report to reduce execution time. Using a 14 TB ZBC disk, these simple changes reduce device scan time at boot from about 3.5s down to about 900ms. Disk revalidate times are also reduced from about 450ms down to 230ms. Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Hannes Reinecke <hare@suse.com> Acked-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 7f9d35d commit d2e428e

File tree

1 file changed

+40
-54
lines changed

1 file changed

+40
-54
lines changed

drivers/scsi/sd_zbc.c

Lines changed: 40 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,17 @@ static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf,
6767
* @buf: Buffer to use for the reply
6868
* @buflen: the buffer size
6969
* @lba: Start LBA of the report
70+
* @partial: Do partial report
7071
*
7172
* For internal use during device validation.
73+
* Using partial=true can significantly speed up execution of a report zones
74+
* command because the disk does not have to count all possible report matching
75+
* zones and will only report the count of zones fitting in the command reply
76+
* buffer.
7277
*/
7378
static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
74-
unsigned int buflen, sector_t lba)
79+
unsigned int buflen, sector_t lba,
80+
bool partial)
7581
{
7682
struct scsi_device *sdp = sdkp->device;
7783
const int timeout = sdp->request_queue->rq_timeout;
@@ -85,6 +91,8 @@ static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
8591
cmd[1] = ZI_REPORT_ZONES;
8692
put_unaligned_be64(lba, &cmd[2]);
8793
put_unaligned_be32(buflen, &cmd[10]);
94+
if (partial)
95+
cmd[14] = ZBC_REPORT_ZONE_PARTIAL;
8896
memset(buf, 0, buflen);
8997

9098
result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
@@ -350,60 +358,25 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
350358
return 0;
351359
}
352360

353-
/**
354-
* sd_zbc_check_capacity - Check reported capacity.
355-
* @sdkp: Target disk
356-
* @buf: Buffer to use for commands
357-
*
358-
* ZBC drive may report only the capacity of the first conventional zones at
359-
* LBA 0. This is indicated by the RC_BASIS field of the read capacity reply.
360-
* Check this here. If the disk reported only its conventional zones capacity,
361-
* get the total capacity by doing a report zones.
362-
*/
363-
static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf)
364-
{
365-
sector_t lba;
366-
int ret;
367-
368-
if (sdkp->rc_basis != 0)
369-
return 0;
370-
371-
/* Do a report zone to get the maximum LBA to check capacity */
372-
ret = sd_zbc_report_zones(sdkp, buf, SD_BUF_SIZE, 0);
373-
if (ret)
374-
return ret;
375-
376-
/* The max_lba field is the capacity of this device */
377-
lba = get_unaligned_be64(&buf[8]);
378-
if (lba + 1 == sdkp->capacity)
379-
return 0;
380-
381-
if (sdkp->first_scan)
382-
sd_printk(KERN_WARNING, sdkp,
383-
"Changing capacity from %llu to max LBA+1 %llu\n",
384-
(unsigned long long)sdkp->capacity,
385-
(unsigned long long)lba + 1);
386-
sdkp->capacity = lba + 1;
387-
388-
return 0;
389-
}
390-
391361
#define SD_ZBC_BUF_SIZE 131072U
392362

393363
/**
394-
* sd_zbc_check_zone_size - Check the device zone sizes
364+
* sd_zbc_check_zones - Check the device capacity and zone sizes
395365
* @sdkp: Target disk
396366
*
397-
* Check that all zones of the device are equal. The last zone can however
398-
* be smaller. The zone size must also be a power of two number of LBAs.
367+
* Check that the device capacity as reported by READ CAPACITY matches the
368+
* max_lba value (plus one)of the report zones command reply. Also check that
369+
* all zones of the device have an equal size, only allowing the last zone of
370+
* the disk to have a smaller size (runt zone). The zone size must also be a
371+
* power of two.
399372
*
400373
* Returns the zone size in number of blocks upon success or an error code
401374
* upon failure.
402375
*/
403-
static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
376+
static s64 sd_zbc_check_zones(struct scsi_disk *sdkp)
404377
{
405378
u64 zone_blocks = 0;
406-
sector_t block = 0;
379+
sector_t max_lba, block = 0;
407380
unsigned char *buf;
408381
unsigned char *rec;
409382
unsigned int buf_len;
@@ -416,11 +389,28 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
416389
if (!buf)
417390
return -ENOMEM;
418391

419-
/* Do a report zone to get the same field */
420-
ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0);
392+
/* Do a report zone to get max_lba and the same field */
393+
ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false);
421394
if (ret)
422395
goto out_free;
423396

397+
if (sdkp->rc_basis == 0) {
398+
/* The max_lba field is the capacity of this device */
399+
max_lba = get_unaligned_be64(&buf[8]);
400+
if (sdkp->capacity != max_lba + 1) {
401+
if (sdkp->first_scan)
402+
sd_printk(KERN_WARNING, sdkp,
403+
"Changing capacity from %llu to max LBA+1 %llu\n",
404+
(unsigned long long)sdkp->capacity,
405+
(unsigned long long)max_lba + 1);
406+
sdkp->capacity = max_lba + 1;
407+
}
408+
}
409+
410+
/*
411+
* Check same field: for any value other than 0, we know that all zones
412+
* have the same size.
413+
*/
424414
same = buf[4] & 0x0f;
425415
if (same > 0) {
426416
rec = &buf[64];
@@ -458,7 +448,7 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
458448

459449
if (block < sdkp->capacity) {
460450
ret = sd_zbc_report_zones(sdkp, buf,
461-
SD_ZBC_BUF_SIZE, block);
451+
SD_ZBC_BUF_SIZE, block, true);
462452
if (ret)
463453
goto out_free;
464454
}
@@ -574,7 +564,8 @@ sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp, u32 zone_shift,
574564
goto out;
575565

576566
while (lba < sdkp->capacity) {
577-
ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, lba);
567+
ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
568+
lba, true);
578569
if (ret)
579570
goto out;
580571
lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
@@ -692,16 +683,11 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
692683
if (ret)
693684
goto err;
694685

695-
/* Check capacity */
696-
ret = sd_zbc_check_capacity(sdkp, buf);
697-
if (ret)
698-
goto err;
699-
700686
/*
701687
* Check zone size: only devices with a constant zone size (except
702688
* an eventual last runt zone) that is a power of 2 are supported.
703689
*/
704-
zone_blocks = sd_zbc_check_zone_size(sdkp);
690+
zone_blocks = sd_zbc_check_zones(sdkp);
705691
ret = -EFBIG;
706692
if (zone_blocks != (u32)zone_blocks)
707693
goto err;

0 commit comments

Comments
 (0)