* [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.