All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] 4.14 long term stable ZBC fixes
@ 2018-06-04  8:04 Damien Le Moal
  2018-06-04  8:04 ` [PATCH v2 1/2] scsi: sd_zbc: Fix potential memory leak Damien Le Moal
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Damien Le Moal @ 2018-06-04  8:04 UTC (permalink / raw)
  To: linux-scsi, Martin K . Petersen
  Cc: stable, Greg Kroah-Hartman, Bart Van Assche, Hannes Reinecke

Patch 4b433924b275 ("scsi: sd_zbc: Fix potential memory leak") was added in
4.16 and 4.15 stable but did not make it to long term stable 4.14 (as far as I
can tell).

Patch ccce20fc7968 ("scsi: sd_zbc: Avoid that resetting a zone fails
sporadically") is included in 4.16 but does not apply to 4.15 stable nor to
4.14 long term stable and requires extensive modifications.

This small series provides a backport of both patches against 4.14. Please
consider these patches for inclusion in this long term stable kernel.

Bart Van Assche (1):
  scsi: sd_zbc: Avoid that resetting a zone fails sporadically

Damien Le Moal (1):
  scsi: sd_zbc: Fix potential memory leak

 drivers/scsi/sd_zbc.c | 128 +++++++++++++++++++++++++-----------------
 1 file changed, 76 insertions(+), 52 deletions(-)

Changes from v1:
* Fixed upstream commit reference in the first patch commit message

-- 
2.17.0

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/2] scsi: sd_zbc: Fix potential memory leak
  2018-06-04  8:04 [PATCH v2 0/2] 4.14 long term stable ZBC fixes Damien Le Moal
@ 2018-06-04  8:04 ` Damien Le Moal
  2018-06-04  8:04 ` [PATCH v2 2/2] scsi: sd_zbc: Avoid that resetting a zone fails sporadically Damien Le Moal
  2018-06-05 10:18 ` [PATCH v2 0/2] 4.14 long term stable ZBC fixes Greg Kroah-Hartman
  2 siblings, 0 replies; 4+ messages in thread
From: Damien Le Moal @ 2018-06-04  8:04 UTC (permalink / raw)
  To: linux-scsi, Martin K . Petersen
  Cc: stable, Greg Kroah-Hartman, Bart Van Assche, Hannes Reinecke

[Backport of upstream commit 4b433924b2755a94f99258c178684a0e05c344de]

Rework sd_zbc_check_zone_size() to avoid a memory leak due to an early
return if sd_zbc_report_zones() fails.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Cc: stable@vger.kernel.org # 4.14
---
 drivers/scsi/sd_zbc.c | 34 +++++++++++++++-------------------
 1 file changed, 15 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 2eb61d54bbb4..bc3cb81a9c7d 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -425,7 +425,7 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp,
 
 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 scsi_disk *sdkp)
 
 	/* 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 scsi_disk *sdkp)
 			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 scsi_disk *sdkp)
 	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)
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/2] scsi: sd_zbc: Avoid that resetting a zone fails sporadically
  2018-06-04  8:04 [PATCH v2 0/2] 4.14 long term stable ZBC fixes Damien Le Moal
  2018-06-04  8:04 ` [PATCH v2 1/2] scsi: sd_zbc: Fix potential memory leak Damien Le Moal
@ 2018-06-04  8:04 ` Damien Le Moal
  2018-06-05 10:18 ` [PATCH v2 0/2] 4.14 long term stable ZBC fixes Greg Kroah-Hartman
  2 siblings, 0 replies; 4+ messages in thread
From: Damien Le Moal @ 2018-06-04  8:04 UTC (permalink / raw)
  To: linux-scsi, Martin K . Petersen
  Cc: stable, Greg Kroah-Hartman, Bart Van Assche, Hannes Reinecke,
	Bart Van Assche

From: Bart Van Assche <bart.vanassche@wdc.com>

[Backport of upstream commit ccce20fc7968d546fb1e8e147bf5cdc8afc4278a]

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() sets sdkp->nr_zones to zero before restoring it to
the actual value, even if no drive characteristics have changed.
Avoid that this can happen by modifying making the following changes:

- Protect the code that updates zone information with blk_mq_freeze()
  and blk_mq_unfreeze().
- Modify sd_zbc_setup() such that these functions do not modify
  struct scsi_disk before all zone information has been obtained.
- Reallocate the zone write lock bitmap if the number of zones changed.

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 <bart.vanassche@wdc.com>
[Damien]
* Backport for 4.14-stable
* Updated this commit message
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Cc: stable@vger.kernel.org # 4.14
---
 drivers/scsi/sd_zbc.c | 98 +++++++++++++++++++++++++++----------------
 1 file changed, 63 insertions(+), 35 deletions(-)

diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index bc3cb81a9c7d..ea9e1e0ed5b8 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -423,7 +423,16 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp,
 
 #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 scsi_disk *sdkp)
 	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 scsi_disk *sdkp)
 
 		/* 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 scsi_disk *sdkp)
 
 	} while (block < sdkp->capacity);
 
-	zone_blocks = sdkp->zone_blocks;
-
 out:
 	if (!zone_blocks) {
 		if (sdkp->first_scan)
@@ -513,8 +519,7 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
 				  "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 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
 	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 *sdkp)
 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 *sdkp,
 	 * 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 *sdkp)
 {
 	kfree(sdkp->zones_wlock);
 	sdkp->zones_wlock = NULL;
+	sdkp->nr_zones = 0;
 }
 
 void sd_zbc_print_zones(struct scsi_disk *sdkp)
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 0/2] 4.14 long term stable ZBC fixes
  2018-06-04  8:04 [PATCH v2 0/2] 4.14 long term stable ZBC fixes Damien Le Moal
  2018-06-04  8:04 ` [PATCH v2 1/2] scsi: sd_zbc: Fix potential memory leak Damien Le Moal
  2018-06-04  8:04 ` [PATCH v2 2/2] scsi: sd_zbc: Avoid that resetting a zone fails sporadically Damien Le Moal
@ 2018-06-05 10:18 ` Greg Kroah-Hartman
  2 siblings, 0 replies; 4+ messages in thread
From: Greg Kroah-Hartman @ 2018-06-05 10:18 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: linux-scsi, Martin K . Petersen, stable, Bart Van Assche,
	Hannes Reinecke

On Mon, Jun 04, 2018 at 05:04:11PM +0900, Damien Le Moal wrote:
> Patch 4b433924b275 ("scsi: sd_zbc: Fix potential memory leak") was added in
> 4.16 and 4.15 stable but did not make it to long term stable 4.14 (as far as I
> can tell).
> 
> Patch ccce20fc7968 ("scsi: sd_zbc: Avoid that resetting a zone fails
> sporadically") is included in 4.16 but does not apply to 4.15 stable nor to
> 4.14 long term stable and requires extensive modifications.
> 
> This small series provides a backport of both patches against 4.14. Please
> consider these patches for inclusion in this long term stable kernel.

Both now queued up, thanks.

greg k-h

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-06-05 10:18 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-04  8:04 [PATCH v2 0/2] 4.14 long term stable ZBC fixes Damien Le Moal
2018-06-04  8:04 ` [PATCH v2 1/2] scsi: sd_zbc: Fix potential memory leak Damien Le Moal
2018-06-04  8:04 ` [PATCH v2 2/2] scsi: sd_zbc: Avoid that resetting a zone fails sporadically Damien Le Moal
2018-06-05 10:18 ` [PATCH v2 0/2] 4.14 long term stable ZBC fixes Greg Kroah-Hartman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.