Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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/20200731054928.668547-1-damien.lemoal@wdc.com
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Damien Le Moal and committed by
Martin K. Petersen
a3d8a257 ec007ef4

+60 -54
+8 -2
drivers/scsi/sd.c
··· 2578 2578 sd_printk(KERN_NOTICE, sdkp, 2579 2579 "%u-byte physical blocks\n", 2580 2580 sdkp->physical_block_size); 2581 - 2582 - sd_zbc_print_zones(sdkp); 2583 2581 } 2584 2582 2585 2583 /* called with buffer of length 512 */ ··· 3217 3219 logical_to_sectors(sdp, sdkp->capacity), false); 3218 3220 sd_config_write_same(sdkp); 3219 3221 kfree(buffer); 3222 + 3223 + /* 3224 + * For a zoned drive, revalidating the zones can be done only once 3225 + * the gendisk capacity is set. So if this fails, set back the gendisk 3226 + * capacity to 0. 3227 + */ 3228 + if (sd_zbc_revalidate_zones(sdkp)) 3229 + set_capacity_revalidate_and_notify(disk, 0, false); 3220 3230 3221 3231 out: 3222 3232 return 0;
+8 -3
drivers/scsi/sd.h
··· 75 75 struct opal_dev *opal_dev; 76 76 #ifdef CONFIG_BLK_DEV_ZONED 77 77 u32 nr_zones; 78 + u32 rev_nr_zones; 78 79 u32 zone_blocks; 80 + u32 rev_zone_blocks; 79 81 u32 zones_optimal_open; 80 82 u32 zones_optimal_nonseq; 81 83 u32 zones_max_open; ··· 217 215 218 216 int sd_zbc_init_disk(struct scsi_disk *sdkp); 219 217 void sd_zbc_release_disk(struct scsi_disk *sdkp); 220 - extern int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer); 221 - extern void sd_zbc_print_zones(struct scsi_disk *sdkp); 218 + int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer); 219 + int sd_zbc_revalidate_zones(struct scsi_disk *sdkp); 222 220 blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, 223 221 unsigned char op, bool all); 224 222 unsigned int sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, ··· 244 242 return 0; 245 243 } 246 244 247 - static inline void sd_zbc_print_zones(struct scsi_disk *sdkp) {} 245 + static inline int sd_zbc_revalidate_zones(struct scsi_disk *sdkp) 246 + { 247 + return 0; 248 + } 248 249 249 250 static inline blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, 250 251 unsigned char op,
+44 -49
drivers/scsi/sd_zbc.c
··· 633 633 return 0; 634 634 } 635 635 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 + 636 653 static void sd_zbc_revalidate_zones_cb(struct gendisk *disk) 637 654 { 638 655 struct scsi_disk *sdkp = scsi_disk(disk); ··· 657 640 swap(sdkp->zones_wp_offset, sdkp->rev_wp_offset); 658 641 } 659 642 660 - static int sd_zbc_revalidate_zones(struct scsi_disk *sdkp, 661 - u32 zone_blocks, 662 - unsigned int nr_zones) 643 + int sd_zbc_revalidate_zones(struct scsi_disk *sdkp) 663 644 { 664 645 struct gendisk *disk = sdkp->disk; 646 + struct request_queue *q = disk->queue; 647 + u32 zone_blocks = sdkp->rev_zone_blocks; 648 + unsigned int nr_zones = sdkp->rev_nr_zones; 649 + u32 max_append; 665 650 int ret = 0; 651 + 652 + if (!sd_is_zoned(sdkp)) 653 + return 0; 666 654 667 655 /* 668 656 * Make sure revalidate zones are serialized to ensure exclusive ··· 675 653 */ 676 654 mutex_lock(&sdkp->rev_mutex); 677 655 678 - /* 679 - * Revalidate the disk zones to update the device request queue zone 680 - * bitmaps and the zone write pointer offset array. Do this only once 681 - * the device capacity is set on the second revalidate execution for 682 - * disk scan or if something changed when executing a normal revalidate. 683 - */ 684 - if (sdkp->first_scan) { 685 - sdkp->zone_blocks = zone_blocks; 686 - sdkp->nr_zones = nr_zones; 687 - goto unlock; 688 - } 689 - 690 656 if (sdkp->zone_blocks == zone_blocks && 691 657 sdkp->nr_zones == nr_zones && 692 658 disk->queue->nr_zones == nr_zones) 693 659 goto unlock; 694 660 661 + sdkp->zone_blocks = zone_blocks; 662 + sdkp->nr_zones = nr_zones; 695 663 sdkp->rev_wp_offset = kvcalloc(nr_zones, sizeof(u32), GFP_NOIO); 696 664 if (!sdkp->rev_wp_offset) { 697 665 ret = -ENOMEM; ··· 692 680 693 681 kvfree(sdkp->rev_wp_offset); 694 682 sdkp->rev_wp_offset = NULL; 683 + 684 + if (ret) { 685 + sdkp->zone_blocks = 0; 686 + sdkp->nr_zones = 0; 687 + sdkp->capacity = 0; 688 + goto unlock; 689 + } 690 + 691 + max_append = min_t(u32, logical_to_sectors(sdkp->device, zone_blocks), 692 + q->limits.max_segments << (PAGE_SHIFT - 9)); 693 + max_append = min_t(u32, max_append, queue_max_hw_sectors(q)); 694 + 695 + blk_queue_max_zone_append_sectors(q, max_append); 696 + 697 + sd_zbc_print_zones(sdkp); 695 698 696 699 unlock: 697 700 mutex_unlock(&sdkp->rev_mutex); ··· 720 693 struct request_queue *q = disk->queue; 721 694 unsigned int nr_zones; 722 695 u32 zone_blocks = 0; 723 - u32 max_append; 724 696 int ret; 725 697 726 698 if (!sd_is_zoned(sdkp)) ··· 748 722 sdkp->device->use_16_for_rw = 1; 749 723 sdkp->device->use_10_for_rw = 0; 750 724 751 - ret = sd_zbc_revalidate_zones(sdkp, zone_blocks, nr_zones); 752 - if (ret) 753 - goto err; 754 - 755 - /* 756 - * On the first scan 'chunk_sectors' isn't setup yet, so calling 757 - * blk_queue_max_zone_append_sectors() will result in a WARN(). Defer 758 - * this setting to the second scan. 759 - */ 760 - if (sdkp->first_scan) 761 - return 0; 762 - 763 - max_append = min_t(u32, logical_to_sectors(sdkp->device, zone_blocks), 764 - q->limits.max_segments << (PAGE_SHIFT - 9)); 765 - 766 - blk_queue_max_zone_append_sectors(q, max_append); 725 + sdkp->rev_nr_zones = nr_zones; 726 + sdkp->rev_zone_blocks = zone_blocks; 767 727 768 728 return 0; 769 729 ··· 757 745 sdkp->capacity = 0; 758 746 759 747 return ret; 760 - } 761 - 762 - void sd_zbc_print_zones(struct scsi_disk *sdkp) 763 - { 764 - if (!sd_is_zoned(sdkp) || !sdkp->capacity) 765 - return; 766 - 767 - if (sdkp->capacity & (sdkp->zone_blocks - 1)) 768 - sd_printk(KERN_NOTICE, sdkp, 769 - "%u zones of %u logical blocks + 1 runt zone\n", 770 - sdkp->nr_zones - 1, 771 - sdkp->zone_blocks); 772 - else 773 - sd_printk(KERN_NOTICE, sdkp, 774 - "%u zones of %u logical blocks\n", 775 - sdkp->nr_zones, 776 - sdkp->zone_blocks); 777 748 } 778 749 779 750 int sd_zbc_init_disk(struct scsi_disk *sdkp)