Commit 6c5dee18 authored by Damien Le Moal's avatar Damien Le Moal Committed by Martin K. Petersen

scsi: sd: sd_zbc: Fix ZBC disk initialization

Make sure to call sd_zbc_init_disk() when the sdkp->zoned field is known,
that is, once sd_read_block_characteristics() is executed in
sd_revalidate_disk(), so that host-aware disks also get initialized.  To do
so, move sd_zbc_init_disk() call in sd_zbc_revalidate_zones() and make sure
to execute it for all zoned disks, including for host-aware disks used as
regular disks as these disk zoned model may be changed back to BLK_ZONED_HA
when partitions are deleted.

Link: https://lore.kernel.org/r/20200915073347.832424-3-damien.lemoal@wdc.com
Fixes: 5795eb44 ("scsi: sd_zbc: emulate ZONE_APPEND commands")
Cc: <stable@vger.kernel.org> # v5.8+
Reported-by: default avatarBorislav Petkov <bp@alien8.de>
Tested-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDamien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 27ba3e8f
...@@ -3410,10 +3410,6 @@ static int sd_probe(struct device *dev) ...@@ -3410,10 +3410,6 @@ static int sd_probe(struct device *dev)
sdkp->first_scan = 1; sdkp->first_scan = 1;
sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS; sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS;
error = sd_zbc_init_disk(sdkp);
if (error)
goto out_free_index;
sd_revalidate_disk(gd); sd_revalidate_disk(gd);
gd->flags = GENHD_FL_EXT_DEVT; gd->flags = GENHD_FL_EXT_DEVT;
......
...@@ -215,7 +215,6 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp) ...@@ -215,7 +215,6 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp)
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
int sd_zbc_init_disk(struct scsi_disk *sdkp);
void sd_zbc_release_disk(struct scsi_disk *sdkp); void sd_zbc_release_disk(struct scsi_disk *sdkp);
int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer); int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer);
int sd_zbc_revalidate_zones(struct scsi_disk *sdkp); int sd_zbc_revalidate_zones(struct scsi_disk *sdkp);
...@@ -231,11 +230,6 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba, ...@@ -231,11 +230,6 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba,
#else /* CONFIG_BLK_DEV_ZONED */ #else /* CONFIG_BLK_DEV_ZONED */
static inline int sd_zbc_init_disk(struct scsi_disk *sdkp)
{
return 0;
}
static inline void sd_zbc_release_disk(struct scsi_disk *sdkp) {} static inline void sd_zbc_release_disk(struct scsi_disk *sdkp) {}
static inline int sd_zbc_read_zones(struct scsi_disk *sdkp, static inline int sd_zbc_read_zones(struct scsi_disk *sdkp,
......
...@@ -651,6 +651,28 @@ static void sd_zbc_print_zones(struct scsi_disk *sdkp) ...@@ -651,6 +651,28 @@ static void sd_zbc_print_zones(struct scsi_disk *sdkp)
sdkp->zone_blocks); sdkp->zone_blocks);
} }
static int sd_zbc_init_disk(struct scsi_disk *sdkp)
{
sdkp->zones_wp_offset = NULL;
spin_lock_init(&sdkp->zones_wp_offset_lock);
sdkp->rev_wp_offset = NULL;
mutex_init(&sdkp->rev_mutex);
INIT_WORK(&sdkp->zone_wp_offset_work, sd_zbc_update_wp_offset_workfn);
sdkp->zone_wp_update_buf = kzalloc(SD_BUF_SIZE, GFP_KERNEL);
if (!sdkp->zone_wp_update_buf)
return -ENOMEM;
return 0;
}
void sd_zbc_release_disk(struct scsi_disk *sdkp)
{
kvfree(sdkp->zones_wp_offset);
sdkp->zones_wp_offset = NULL;
kfree(sdkp->zone_wp_update_buf);
sdkp->zone_wp_update_buf = NULL;
}
static void sd_zbc_revalidate_zones_cb(struct gendisk *disk) static void sd_zbc_revalidate_zones_cb(struct gendisk *disk)
{ {
struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_disk *sdkp = scsi_disk(disk);
...@@ -667,6 +689,19 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp) ...@@ -667,6 +689,19 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
u32 max_append; u32 max_append;
int ret = 0; int ret = 0;
/*
* For all zoned disks, initialize zone append emulation data if not
* already done. This is necessary also for host-aware disks used as
* regular disks due to the presence of partitions as these partitions
* may be deleted and the disk zoned model changed back from
* BLK_ZONED_NONE to BLK_ZONED_HA.
*/
if (sd_is_zoned(sdkp) && !sdkp->zone_wp_update_buf) {
ret = sd_zbc_init_disk(sdkp);
if (ret)
return ret;
}
/* /*
* There is nothing to do for regular disks, including host-aware disks * There is nothing to do for regular disks, including host-aware disks
* that have partitions. * that have partitions.
...@@ -768,28 +803,3 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) ...@@ -768,28 +803,3 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
return ret; return ret;
} }
int sd_zbc_init_disk(struct scsi_disk *sdkp)
{
if (!sd_is_zoned(sdkp))
return 0;
sdkp->zones_wp_offset = NULL;
spin_lock_init(&sdkp->zones_wp_offset_lock);
sdkp->rev_wp_offset = NULL;
mutex_init(&sdkp->rev_mutex);
INIT_WORK(&sdkp->zone_wp_offset_work, sd_zbc_update_wp_offset_workfn);
sdkp->zone_wp_update_buf = kzalloc(SD_BUF_SIZE, GFP_KERNEL);
if (!sdkp->zone_wp_update_buf)
return -ENOMEM;
return 0;
}
void sd_zbc_release_disk(struct scsi_disk *sdkp)
{
kvfree(sdkp->zones_wp_offset);
sdkp->zones_wp_offset = NULL;
kfree(sdkp->zone_wp_update_buf);
sdkp->zone_wp_update_buf = NULL;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment