]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 7 Oct 2020 06:02:54 +0000 (08:02 +0200)
commit 6c5dee18756b4721ac8518c69b22ee8ac0c9c442 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/sd_zbc.c

index 0e1bd2e0475aa8c231e9790f8111ea98baebf4fd..4b2117cb84837a31151119b82dc4739bc0891eb0 100644 (file)
@@ -3404,10 +3404,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 e23d8e4ff654e1745166d3dd497ddc186791e2e6..9c24de305c6b98079fcd335c2442d342d7bd8691 100644 (file)
@@ -213,7 +213,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);
 extern int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer);
 extern void sd_zbc_print_zones(struct scsi_disk *sdkp);
@@ -229,17 +228,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(void)
-{
-       return 0;
-}
-
-static inline int sd_zbc_init_disk(struct scsi_disk *sdkp)
-{
-       return 0;
-}
-
-static inline void sd_zbc_exit(void) {}
 static inline void sd_zbc_release_disk(struct scsi_disk *sdkp) {}
 
 static inline int sd_zbc_read_zones(struct scsi_disk *sdkp,
index 9618eea2a638504d7f8337d1ab52469136ec9e7c..8384b5dcfa029399ebf9ce4905767e8b2a1c4fab 100644 (file)
@@ -633,6 +633,45 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf,
        return 0;
 }
 
+void sd_zbc_print_zones(struct scsi_disk *sdkp)
+{
+       if (!sd_is_zoned(sdkp) || !sdkp->capacity)
+               return;
+
+       if (sdkp->capacity & (sdkp->zone_blocks - 1))
+               sd_printk(KERN_NOTICE, sdkp,
+                         "%u zones of %u logical blocks + 1 runt zone\n",
+                         sdkp->nr_zones - 1,
+                         sdkp->zone_blocks);
+       else
+               sd_printk(KERN_NOTICE, sdkp,
+                         "%u zones of %u logical blocks\n",
+                         sdkp->nr_zones,
+                         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);
@@ -649,6 +688,19 @@ static 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.
@@ -754,45 +806,3 @@ err:
 
        return ret;
 }
-
-void sd_zbc_print_zones(struct scsi_disk *sdkp)
-{
-       if (!sd_is_zoned(sdkp) || !sdkp->capacity)
-               return;
-
-       if (sdkp->capacity & (sdkp->zone_blocks - 1))
-               sd_printk(KERN_NOTICE, sdkp,
-                         "%u zones of %u logical blocks + 1 runt zone\n",
-                         sdkp->nr_zones - 1,
-                         sdkp->zone_blocks);
-       else
-               sd_printk(KERN_NOTICE, sdkp,
-                         "%u zones of %u logical blocks\n",
-                         sdkp->nr_zones,
-                         sdkp->zone_blocks);
-}
-
-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;
-}