Skip to content

Commit a3d8a25

Browse files
damien-lemoalmartinkpetersen
authored andcommitted
scsi: sd_zbc: Improve zone revalidation
Currently, for zoned disks, since blk_revalidate_disk_zones() requires the disk capacity to be set already to operate correctly, zones revalidation can only be done on the second revalidate scan once the gendisk capacity is set at the end of the first scan. As a result, if zone revalidation fails, there is no second chance to recover from the failure and the disk capacity is changed to 0, with the disk left unusable. This can be improved by shuffling around code, specifically, by moving the call to sd_zbc_revalidate_zones() from sd_zbc_read_zones() to the end of sd_revalidate_disk(), after set_capacity_revalidate_and_notify() is called to set the gendisk capacity. With this change, if sd_zbc_revalidate_zones() fails on the first scan, the second scan will call it again to recover, if possible. Using the new struct scsi_disk fields rev_nr_zones and rev_zone_blocks, sd_zbc_revalidate_zones() does actual work only if it detects a change with the disk zone configuration. This means that for a successful zones revalidation on the first scan, the second scan will not cause another heavy full check. While at it, remove the unecesary "extern" declaration of sd_zbc_read_zones(). Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Johannes Thumshirn <[email protected]> Signed-off-by: Damien Le Moal <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent ec007ef commit a3d8a25

File tree

3 files changed

+60
-54
lines changed

3 files changed

+60
-54
lines changed

drivers/scsi/sd.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2578,8 +2578,6 @@ sd_print_capacity(struct scsi_disk *sdkp,
25782578
sd_printk(KERN_NOTICE, sdkp,
25792579
"%u-byte physical blocks\n",
25802580
sdkp->physical_block_size);
2581-
2582-
sd_zbc_print_zones(sdkp);
25832581
}
25842582

25852583
/* called with buffer of length 512 */
@@ -3220,6 +3218,14 @@ static int sd_revalidate_disk(struct gendisk *disk)
32203218
sd_config_write_same(sdkp);
32213219
kfree(buffer);
32223220

3221+
/*
3222+
* For a zoned drive, revalidating the zones can be done only once
3223+
* the gendisk capacity is set. So if this fails, set back the gendisk
3224+
* capacity to 0.
3225+
*/
3226+
if (sd_zbc_revalidate_zones(sdkp))
3227+
set_capacity_revalidate_and_notify(disk, 0, false);
3228+
32233229
out:
32243230
return 0;
32253231
}

drivers/scsi/sd.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ struct scsi_disk {
7575
struct opal_dev *opal_dev;
7676
#ifdef CONFIG_BLK_DEV_ZONED
7777
u32 nr_zones;
78+
u32 rev_nr_zones;
7879
u32 zone_blocks;
80+
u32 rev_zone_blocks;
7981
u32 zones_optimal_open;
8082
u32 zones_optimal_nonseq;
8183
u32 zones_max_open;
@@ -215,8 +217,8 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp)
215217

216218
int sd_zbc_init_disk(struct scsi_disk *sdkp);
217219
void sd_zbc_release_disk(struct scsi_disk *sdkp);
218-
extern int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer);
219-
extern void sd_zbc_print_zones(struct scsi_disk *sdkp);
220+
int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer);
221+
int sd_zbc_revalidate_zones(struct scsi_disk *sdkp);
220222
blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd,
221223
unsigned char op, bool all);
222224
unsigned int sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
@@ -242,7 +244,10 @@ static inline int sd_zbc_read_zones(struct scsi_disk *sdkp,
242244
return 0;
243245
}
244246

245-
static inline void sd_zbc_print_zones(struct scsi_disk *sdkp) {}
247+
static inline int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
248+
{
249+
return 0;
250+
}
246251

247252
static inline blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd,
248253
unsigned char op,

drivers/scsi/sd_zbc.c

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -633,43 +633,55 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf,
633633
return 0;
634634
}
635635

636+
static void sd_zbc_print_zones(struct scsi_disk *sdkp)
637+
{
638+
if (!sd_is_zoned(sdkp) || !sdkp->capacity)
639+
return;
640+
641+
if (sdkp->capacity & (sdkp->zone_blocks - 1))
642+
sd_printk(KERN_NOTICE, sdkp,
643+
"%u zones of %u logical blocks + 1 runt zone\n",
644+
sdkp->nr_zones - 1,
645+
sdkp->zone_blocks);
646+
else
647+
sd_printk(KERN_NOTICE, sdkp,
648+
"%u zones of %u logical blocks\n",
649+
sdkp->nr_zones,
650+
sdkp->zone_blocks);
651+
}
652+
636653
static void sd_zbc_revalidate_zones_cb(struct gendisk *disk)
637654
{
638655
struct scsi_disk *sdkp = scsi_disk(disk);
639656

640657
swap(sdkp->zones_wp_offset, sdkp->rev_wp_offset);
641658
}
642659

643-
static int sd_zbc_revalidate_zones(struct scsi_disk *sdkp,
644-
u32 zone_blocks,
645-
unsigned int nr_zones)
660+
int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
646661
{
647662
struct gendisk *disk = sdkp->disk;
663+
struct request_queue *q = disk->queue;
664+
u32 zone_blocks = sdkp->rev_zone_blocks;
665+
unsigned int nr_zones = sdkp->rev_nr_zones;
666+
u32 max_append;
648667
int ret = 0;
649668

669+
if (!sd_is_zoned(sdkp))
670+
return 0;
671+
650672
/*
651673
* Make sure revalidate zones are serialized to ensure exclusive
652674
* updates of the scsi disk data.
653675
*/
654676
mutex_lock(&sdkp->rev_mutex);
655677

656-
/*
657-
* Revalidate the disk zones to update the device request queue zone
658-
* bitmaps and the zone write pointer offset array. Do this only once
659-
* the device capacity is set on the second revalidate execution for
660-
* disk scan or if something changed when executing a normal revalidate.
661-
*/
662-
if (sdkp->first_scan) {
663-
sdkp->zone_blocks = zone_blocks;
664-
sdkp->nr_zones = nr_zones;
665-
goto unlock;
666-
}
667-
668678
if (sdkp->zone_blocks == zone_blocks &&
669679
sdkp->nr_zones == nr_zones &&
670680
disk->queue->nr_zones == nr_zones)
671681
goto unlock;
672682

683+
sdkp->zone_blocks = zone_blocks;
684+
sdkp->nr_zones = nr_zones;
673685
sdkp->rev_wp_offset = kvcalloc(nr_zones, sizeof(u32), GFP_NOIO);
674686
if (!sdkp->rev_wp_offset) {
675687
ret = -ENOMEM;
@@ -681,6 +693,21 @@ static int sd_zbc_revalidate_zones(struct scsi_disk *sdkp,
681693
kvfree(sdkp->rev_wp_offset);
682694
sdkp->rev_wp_offset = NULL;
683695

696+
if (ret) {
697+
sdkp->zone_blocks = 0;
698+
sdkp->nr_zones = 0;
699+
sdkp->capacity = 0;
700+
goto unlock;
701+
}
702+
703+
max_append = min_t(u32, logical_to_sectors(sdkp->device, zone_blocks),
704+
q->limits.max_segments << (PAGE_SHIFT - 9));
705+
max_append = min_t(u32, max_append, queue_max_hw_sectors(q));
706+
707+
blk_queue_max_zone_append_sectors(q, max_append);
708+
709+
sd_zbc_print_zones(sdkp);
710+
684711
unlock:
685712
mutex_unlock(&sdkp->rev_mutex);
686713

@@ -693,7 +720,6 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
693720
struct request_queue *q = disk->queue;
694721
unsigned int nr_zones;
695722
u32 zone_blocks = 0;
696-
u32 max_append;
697723
int ret;
698724

699725
if (!sd_is_zoned(sdkp))
@@ -722,22 +748,8 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
722748
sdkp->device->use_16_for_rw = 1;
723749
sdkp->device->use_10_for_rw = 0;
724750

725-
ret = sd_zbc_revalidate_zones(sdkp, zone_blocks, nr_zones);
726-
if (ret)
727-
goto err;
728-
729-
/*
730-
* On the first scan 'chunk_sectors' isn't setup yet, so calling
731-
* blk_queue_max_zone_append_sectors() will result in a WARN(). Defer
732-
* this setting to the second scan.
733-
*/
734-
if (sdkp->first_scan)
735-
return 0;
736-
737-
max_append = min_t(u32, logical_to_sectors(sdkp->device, zone_blocks),
738-
q->limits.max_segments << (PAGE_SHIFT - 9));
739-
740-
blk_queue_max_zone_append_sectors(q, max_append);
751+
sdkp->rev_nr_zones = nr_zones;
752+
sdkp->rev_zone_blocks = zone_blocks;
741753

742754
return 0;
743755

@@ -747,23 +759,6 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
747759
return ret;
748760
}
749761

750-
void sd_zbc_print_zones(struct scsi_disk *sdkp)
751-
{
752-
if (!sd_is_zoned(sdkp) || !sdkp->capacity)
753-
return;
754-
755-
if (sdkp->capacity & (sdkp->zone_blocks - 1))
756-
sd_printk(KERN_NOTICE, sdkp,
757-
"%u zones of %u logical blocks + 1 runt zone\n",
758-
sdkp->nr_zones - 1,
759-
sdkp->zone_blocks);
760-
else
761-
sd_printk(KERN_NOTICE, sdkp,
762-
"%u zones of %u logical blocks\n",
763-
sdkp->nr_zones,
764-
sdkp->zone_blocks);
765-
}
766-
767762
int sd_zbc_init_disk(struct scsi_disk *sdkp)
768763
{
769764
if (!sd_is_zoned(sdkp))

0 commit comments

Comments
 (0)