scsi: sd: sd_zbc: Fix ZBC disk initialization
authorDamien Le Moal <damien.lemoal@wdc.com>
Tue, 15 Sep 2020 07:33:47 +0000 (16:33 +0900)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 16 Sep 2020 00:08:15 +0000 (20:08 -0400)
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: 5795eb443060 ("scsi: sd_zbc: emulate ZONE_APPEND commands")
Cc: <stable@vger.kernel.org> # v5.8+
Reported-by: Borislav Petkov <bp@alien8.de>
Tested-by: Borislav Petkov <bp@suse.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/sd_zbc.c

index 06286b6..16503e2 100644 (file)
@@ -3410,10 +3410,6 @@ static int sd_probe(struct device *dev)
        sdkp->first_scan = 1;
        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);
 
        gd->flags = GENHD_FL_EXT_DEVT;
index 7251434..a3aad60 100644 (file)
@@ -215,7 +215,6 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp)
 
 #ifdef CONFIG_BLK_DEV_ZONED
 
-int sd_zbc_init_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_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,
 
 #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 int sd_zbc_read_zones(struct scsi_disk *sdkp,
index a739456..cf07b7f 100644 (file)
@@ -651,6 +651,28 @@ static void sd_zbc_print_zones(struct scsi_disk *sdkp)
                          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)
 {
        struct scsi_disk *sdkp = scsi_disk(disk);
@@ -667,6 +689,19 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
        u32 max_append;
        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
         * that have partitions.
@@ -768,28 +803,3 @@ err:
 
        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;
-}