scsi: sd: sd_zbc: Don't pass GFP_NOIO to kvcalloc
authorJohannes Thumshirn <johannes.thumshirn@wdc.com>
Wed, 17 Feb 2021 13:52:45 +0000 (22:52 +0900)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 23 Feb 2021 03:30:10 +0000 (22:30 -0500)
Dan reported we're passing in GFP_NOIO to kvmalloc() which will then
fallback to doing kmalloc() instead of an optional vmalloc() if the size
exceeds kmalloc()s limits. This will break with drives that have zone
numbers exceeding PAGE_SIZE/sizeof(u32).

Instead of passing in GFP_NOIO, enter an implicit GFP_NOIO allocation
scope.

Link: https://lore.kernel.org/r/YCuvSfKw4qEQBr/t@mwanda
Link: https://lore.kernel.org/r/5a6345e2989fd06c049ac4e4627f6acb492c15b8.1613569821.git.johannes.thumshirn@wdc.com
Fixes: 5795eb443060: ("scsi: sd_zbc: emulate ZONE_APPEND commands")
Cc: Damien Le Moal <Damien.LeMoal@wdc.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/sd_zbc.c

index cf07b7f9357906d875ffd7e3dda16c66b221f49a..87a7274e4632b4f3e9201beefd090b634bb90ee0 100644 (file)
@@ -688,6 +688,7 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
        unsigned int nr_zones = sdkp->rev_nr_zones;
        u32 max_append;
        int ret = 0;
+       unsigned int flags;
 
        /*
         * For all zoned disks, initialize zone append emulation data if not
@@ -720,16 +721,19 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
            disk->queue->nr_zones == nr_zones)
                goto unlock;
 
+       flags = memalloc_noio_save();
        sdkp->zone_blocks = zone_blocks;
        sdkp->nr_zones = nr_zones;
-       sdkp->rev_wp_offset = kvcalloc(nr_zones, sizeof(u32), GFP_NOIO);
+       sdkp->rev_wp_offset = kvcalloc(nr_zones, sizeof(u32), GFP_KERNEL);
        if (!sdkp->rev_wp_offset) {
                ret = -ENOMEM;
+               memalloc_noio_restore(flags);
                goto unlock;
        }
 
        ret = blk_revalidate_disk_zones(disk, sd_zbc_revalidate_zones_cb);
 
+       memalloc_noio_restore(flags);
        kvfree(sdkp->rev_wp_offset);
        sdkp->rev_wp_offset = NULL;