From: Greg Kroah-Hartman Date: Tue, 5 Jun 2018 10:20:34 +0000 (+0200) Subject: 4.14-stable patches X-Git-Tag: v4.9.107~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=91cf523d92136e9217384b8a366b7507f780f6e8;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: scsi-sd_zbc-avoid-that-resetting-a-zone-fails-sporadically.patch scsi-sd_zbc-fix-potential-memory-leak.patch --- diff --git a/queue-4.14/scsi-sd_zbc-avoid-that-resetting-a-zone-fails-sporadically.patch b/queue-4.14/scsi-sd_zbc-avoid-that-resetting-a-zone-fails-sporadically.patch new file mode 100644 index 00000000000..b572c976402 --- /dev/null +++ b/queue-4.14/scsi-sd_zbc-avoid-that-resetting-a-zone-fails-sporadically.patch @@ -0,0 +1,219 @@ +From ccce20fc7968d546fb1e8e147bf5cdc8afc4278a Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Mon, 16 Apr 2018 18:04:41 -0700 +Subject: scsi: sd_zbc: Avoid that resetting a zone fails sporadically + +From: Bart Van Assche + +commit ccce20fc7968d546fb1e8e147bf5cdc8afc4278a upstream. + +Since SCSI scanning occurs asynchronously, since sd_revalidate_disk() is +called from sd_probe_async() and since sd_revalidate_disk() calls +sd_zbc_read_zones() it can happen that sd_zbc_read_zones() is called +concurrently with blkdev_report_zones() and/or blkdev_reset_zones(). That can +cause these functions to fail with -EIO because sd_zbc_read_zones() e.g. sets +q->nr_zones to zero before restoring it to the actual value, even if no drive +characteristics have changed. Avoid that this can happen by making the +following changes: + +- Protect the code that updates zone information with blk_queue_enter() + and blk_queue_exit(). +- Modify sd_zbc_setup_seq_zones_bitmap() and sd_zbc_setup() such that + these functions do not modify struct scsi_disk before all zone + information has been obtained. + +Note: since commit 055f6e18e08f ("block: Make q_usage_counter also track +legacy requests"; kernel v4.15) the request queue freezing mechanism also +affects legacy request queues. + +Fixes: 89d947561077 ("sd: Implement support for ZBC devices") +Signed-off-by: Bart Van Assche +Cc: Jens Axboe +Cc: Damien Le Moal +Cc: Christoph Hellwig +Cc: Hannes Reinecke +Cc: stable@vger.kernel.org # v4.16 +Reviewed-by: Damien Le Moal +Signed-off-by: Martin K. Petersen +Signed-off-by: Damien Le Moal +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/sd_zbc.c | 98 ++++++++++++++++++++++++++++++++------------------ + 1 file changed, 63 insertions(+), 35 deletions(-) + +--- a/drivers/scsi/sd_zbc.c ++++ b/drivers/scsi/sd_zbc.c +@@ -423,7 +423,16 @@ static int sd_zbc_check_capacity(struct + + #define SD_ZBC_BUF_SIZE 131072 + +-static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) ++/** ++ * sd_zbc_check_zone_size - Check the device zone sizes ++ * @sdkp: Target disk ++ * ++ * Check that all zones of the device are equal. The last zone can however ++ * be smaller. The zone size must also be a power of two number of LBAs. ++ * ++ * Returns the zone size in bytes upon success or an error code upon failure. ++ */ ++static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) + { + u64 zone_blocks = 0; + sector_t block = 0; +@@ -434,8 +443,6 @@ static int sd_zbc_check_zone_size(struct + int ret; + u8 same; + +- sdkp->zone_blocks = 0; +- + /* Get a buffer */ + buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); + if (!buf) +@@ -470,16 +477,17 @@ static int sd_zbc_check_zone_size(struct + + /* Parse zone descriptors */ + while (rec < buf + buf_len) { +- zone_blocks = get_unaligned_be64(&rec[8]); +- if (sdkp->zone_blocks == 0) { +- sdkp->zone_blocks = zone_blocks; +- } else if (zone_blocks != sdkp->zone_blocks && +- (block + zone_blocks < sdkp->capacity +- || zone_blocks > sdkp->zone_blocks)) { ++ u64 this_zone_blocks = get_unaligned_be64(&rec[8]); ++ ++ if (zone_blocks == 0) { ++ zone_blocks = this_zone_blocks; ++ } else if (this_zone_blocks != zone_blocks && ++ (block + this_zone_blocks < sdkp->capacity ++ || this_zone_blocks > zone_blocks)) { + zone_blocks = 0; + goto out; + } +- block += zone_blocks; ++ block += this_zone_blocks; + rec += 64; + } + +@@ -492,8 +500,6 @@ static int sd_zbc_check_zone_size(struct + + } while (block < sdkp->capacity); + +- zone_blocks = sdkp->zone_blocks; +- + out: + if (!zone_blocks) { + if (sdkp->first_scan) +@@ -513,8 +519,7 @@ out: + "Zone size too large\n"); + ret = -ENODEV; + } else { +- sdkp->zone_blocks = zone_blocks; +- sdkp->zone_shift = ilog2(zone_blocks); ++ ret = zone_blocks; + } + + out_free: +@@ -523,23 +528,44 @@ out_free: + return ret; + } + +-static int sd_zbc_setup(struct scsi_disk *sdkp) ++static int sd_zbc_setup(struct scsi_disk *sdkp, u32 zone_blocks) + { ++ struct request_queue *q = sdkp->disk->queue; ++ u32 zone_shift = ilog2(zone_blocks); ++ u32 nr_zones; + + /* chunk_sectors indicates the zone size */ +- blk_queue_chunk_sectors(sdkp->disk->queue, +- logical_to_sectors(sdkp->device, sdkp->zone_blocks)); +- sdkp->zone_shift = ilog2(sdkp->zone_blocks); +- sdkp->nr_zones = sdkp->capacity >> sdkp->zone_shift; +- if (sdkp->capacity & (sdkp->zone_blocks - 1)) +- sdkp->nr_zones++; +- +- if (!sdkp->zones_wlock) { +- sdkp->zones_wlock = kcalloc(BITS_TO_LONGS(sdkp->nr_zones), +- sizeof(unsigned long), +- GFP_KERNEL); +- if (!sdkp->zones_wlock) +- return -ENOMEM; ++ blk_queue_chunk_sectors(q, ++ logical_to_sectors(sdkp->device, zone_blocks)); ++ nr_zones = round_up(sdkp->capacity, zone_blocks) >> zone_shift; ++ ++ /* ++ * Initialize the disk zone write lock bitmap if the number ++ * of zones changed. ++ */ ++ if (nr_zones != sdkp->nr_zones) { ++ unsigned long *zones_wlock = NULL; ++ ++ if (nr_zones) { ++ zones_wlock = kcalloc(BITS_TO_LONGS(nr_zones), ++ sizeof(unsigned long), ++ GFP_KERNEL); ++ if (!zones_wlock) ++ return -ENOMEM; ++ } ++ ++ blk_mq_freeze_queue(q); ++ sdkp->zone_blocks = zone_blocks; ++ sdkp->zone_shift = zone_shift; ++ sdkp->nr_zones = nr_zones; ++ swap(sdkp->zones_wlock, zones_wlock); ++ blk_mq_unfreeze_queue(q); ++ ++ kfree(zones_wlock); ++ ++ /* READ16/WRITE16 is mandatory for ZBC disks */ ++ sdkp->device->use_16_for_rw = 1; ++ sdkp->device->use_10_for_rw = 0; + } + + return 0; +@@ -548,6 +574,7 @@ static int sd_zbc_setup(struct scsi_disk + int sd_zbc_read_zones(struct scsi_disk *sdkp, + unsigned char *buf) + { ++ int64_t zone_blocks; + int ret; + + if (!sd_is_zoned(sdkp)) +@@ -585,19 +612,19 @@ int sd_zbc_read_zones(struct scsi_disk * + * Check zone size: only devices with a constant zone size (except + * an eventual last runt zone) that is a power of 2 are supported. + */ +- ret = sd_zbc_check_zone_size(sdkp); +- if (ret) ++ zone_blocks = sd_zbc_check_zone_size(sdkp); ++ ret = -EFBIG; ++ if (zone_blocks != (u32)zone_blocks) ++ goto err; ++ ret = zone_blocks; ++ if (ret < 0) + goto err; + + /* The drive satisfies the kernel restrictions: set it up */ +- ret = sd_zbc_setup(sdkp); ++ ret = sd_zbc_setup(sdkp, zone_blocks); + if (ret) + goto err; + +- /* READ16/WRITE16 is mandatory for ZBC disks */ +- sdkp->device->use_16_for_rw = 1; +- sdkp->device->use_10_for_rw = 0; +- + return 0; + + err: +@@ -610,6 +637,7 @@ void sd_zbc_remove(struct scsi_disk *sdk + { + kfree(sdkp->zones_wlock); + sdkp->zones_wlock = NULL; ++ sdkp->nr_zones = 0; + } + + void sd_zbc_print_zones(struct scsi_disk *sdkp) diff --git a/queue-4.14/scsi-sd_zbc-fix-potential-memory-leak.patch b/queue-4.14/scsi-sd_zbc-fix-potential-memory-leak.patch new file mode 100644 index 00000000000..c6e54dcb6eb --- /dev/null +++ b/queue-4.14/scsi-sd_zbc-fix-potential-memory-leak.patch @@ -0,0 +1,102 @@ +From 4b433924b2755a94f99258c178684a0e05c344de Mon Sep 17 00:00:00 2001 +From: Damien Le Moal +Date: Fri, 2 Mar 2018 07:19:28 +0900 +Subject: scsi: sd_zbc: Fix potential memory leak + +From: Damien Le Moal + +commit 4b433924b2755a94f99258c178684a0e05c344de upstream. + +Rework sd_zbc_check_zone_size() to avoid a memory leak due to an early +return if sd_zbc_report_zones() fails. + +Reported-by: David.butterfield +Signed-off-by: Damien Le Moal +Cc: stable@vger.kernel.org +Reviewed-by: Bart Van Assche +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/sd_zbc.c | 34 +++++++++++++++------------------- + 1 file changed, 15 insertions(+), 19 deletions(-) + +--- a/drivers/scsi/sd_zbc.c ++++ b/drivers/scsi/sd_zbc.c +@@ -425,7 +425,7 @@ static int sd_zbc_check_capacity(struct + + static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) + { +- u64 zone_blocks; ++ u64 zone_blocks = 0; + sector_t block = 0; + unsigned char *buf; + unsigned char *rec; +@@ -443,10 +443,8 @@ static int sd_zbc_check_zone_size(struct + + /* Do a report zone to get the same field */ + ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0); +- if (ret) { +- zone_blocks = 0; +- goto out; +- } ++ if (ret) ++ goto out_free; + + same = buf[4] & 0x0f; + if (same > 0) { +@@ -489,7 +487,7 @@ static int sd_zbc_check_zone_size(struct + ret = sd_zbc_report_zones(sdkp, buf, + SD_ZBC_BUF_SIZE, block); + if (ret) +- return ret; ++ goto out_free; + } + + } while (block < sdkp->capacity); +@@ -497,34 +495,32 @@ static int sd_zbc_check_zone_size(struct + zone_blocks = sdkp->zone_blocks; + + out: +- kfree(buf); +- + if (!zone_blocks) { + if (sdkp->first_scan) + sd_printk(KERN_NOTICE, sdkp, + "Devices with non constant zone " + "size are not supported\n"); +- return -ENODEV; +- } +- +- if (!is_power_of_2(zone_blocks)) { ++ ret = -ENODEV; ++ } else if (!is_power_of_2(zone_blocks)) { + if (sdkp->first_scan) + sd_printk(KERN_NOTICE, sdkp, + "Devices with non power of 2 zone " + "size are not supported\n"); +- return -ENODEV; +- } +- +- if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { ++ ret = -ENODEV; ++ } else if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { + if (sdkp->first_scan) + sd_printk(KERN_NOTICE, sdkp, + "Zone size too large\n"); +- return -ENODEV; ++ ret = -ENODEV; ++ } else { ++ sdkp->zone_blocks = zone_blocks; ++ sdkp->zone_shift = ilog2(zone_blocks); + } + +- sdkp->zone_blocks = zone_blocks; ++out_free: ++ kfree(buf); + +- return 0; ++ return ret; + } + + static int sd_zbc_setup(struct scsi_disk *sdkp) diff --git a/queue-4.14/series b/queue-4.14/series new file mode 100644 index 00000000000..9bea165ca91 --- /dev/null +++ b/queue-4.14/series @@ -0,0 +1,2 @@ +scsi-sd_zbc-fix-potential-memory-leak.patch +scsi-sd_zbc-avoid-that-resetting-a-zone-fails-sporadically.patch diff --git a/queue-4.16/series b/queue-4.16/series new file mode 100644 index 00000000000..e69de29bb2d