From: Linus Torvalds Date: Thu, 15 Mar 2018 00:02:49 +0000 (-0700) Subject: Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=0aa3fdb8b3a6df3c2e3b61dbfe079db9d30e03cd;p=linux.git Merge tag 'scsi-fixes' of git://git./linux/kernel/git/jejb/scsi Pull SCSI fixes from James Bottomley: "This is four patches, consisting of one regression from the merge window (qla2xxx), one long-standing memory leak (sd_zbc), one event queue mislabelling which we want to eliminate to discourage the pattern (mpt3sas), and one behaviour change because re-reading the partition table shouldn't clear the ro flag" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: sd: Keep disk read-only when re-reading partition scsi: qla2xxx: Fix crashes in qla2x00_probe_one on probe failure scsi: sd_zbc: Fix potential memory leak scsi: mpt3sas: Do not mark fw_event workqueue as WQ_MEM_RECLAIM --- 0aa3fdb8b3a6df3c2e3b61dbfe079db9d30e03cd diff --cc drivers/scsi/sd_zbc.c index 6c348a211ebb1,9049a189c8e5f..89cf4498f5358 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@@ -494,132 -569,20 +486,135 @@@ out 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; - sdkp->zone_shift = ilog2(zone_blocks); + out_free: + kfree(buf); - return 0; + return ret; } +/** + * sd_zbc_alloc_zone_bitmap - Allocate a zone bitmap (one bit per zone). + * @sdkp: The disk of the bitmap + */ +static inline unsigned long *sd_zbc_alloc_zone_bitmap(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + + return kzalloc_node(BITS_TO_LONGS(sdkp->nr_zones) + * sizeof(unsigned long), + GFP_KERNEL, q->node); +} + +/** + * sd_zbc_get_seq_zones - Parse report zones reply to identify sequential zones + * @sdkp: disk used + * @buf: report reply buffer + * @seq_zone_bitamp: bitmap of sequential zones to set + * + * Parse reported zone descriptors in @buf to identify sequential zones and + * set the reported zone bit in @seq_zones_bitmap accordingly. + * Since read-only and offline zones cannot be written, do not + * mark them as sequential in the bitmap. + * Return the LBA after the last zone reported. + */ +static sector_t sd_zbc_get_seq_zones(struct scsi_disk *sdkp, unsigned char *buf, + unsigned int buflen, + unsigned long *seq_zones_bitmap) +{ + sector_t lba, next_lba = sdkp->capacity; + unsigned int buf_len, list_length; + unsigned char *rec; + u8 type, cond; + + list_length = get_unaligned_be32(&buf[0]) + 64; + buf_len = min(list_length, buflen); + rec = buf + 64; + + while (rec < buf + buf_len) { + type = rec[0] & 0x0f; + cond = (rec[1] >> 4) & 0xf; + lba = get_unaligned_be64(&rec[16]); + if (type != ZBC_ZONE_TYPE_CONV && + cond != ZBC_ZONE_COND_READONLY && + cond != ZBC_ZONE_COND_OFFLINE) + set_bit(lba >> sdkp->zone_shift, seq_zones_bitmap); + next_lba = lba + get_unaligned_be64(&rec[8]); + rec += 64; + } + + return next_lba; +} + +/** + * sd_zbc_setup_seq_zones_bitmap - Initialize the disk seq zone bitmap. + * @sdkp: target disk + * + * Allocate a zone bitmap and initialize it by identifying sequential zones. + */ +static int sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + unsigned long *seq_zones_bitmap; + sector_t lba = 0; + unsigned char *buf; + int ret = -ENOMEM; + + seq_zones_bitmap = sd_zbc_alloc_zone_bitmap(sdkp); + if (!seq_zones_bitmap) + return -ENOMEM; + + buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); + if (!buf) + goto out; + + while (lba < sdkp->capacity) { + ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, lba); + if (ret) + goto out; + lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE, + seq_zones_bitmap); + } + + if (lba != sdkp->capacity) { + /* Something went wrong */ + ret = -EIO; + } + +out: + kfree(buf); + if (ret) { + kfree(seq_zones_bitmap); + return ret; + } + + q->seq_zones_bitmap = seq_zones_bitmap; + + return 0; +} + +static void sd_zbc_cleanup(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + + kfree(q->seq_zones_bitmap); + q->seq_zones_bitmap = NULL; + + kfree(q->seq_zones_wlock); + q->seq_zones_wlock = NULL; + + q->nr_zones = 0; +} + static int sd_zbc_setup(struct scsi_disk *sdkp) { + struct request_queue *q = sdkp->disk->queue; + int ret; /* READ16/WRITE16 is mandatory for ZBC disks */ sdkp->device->use_16_for_rw = 1;