From patchwork Mon Aug 6 04:51:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Gilbert X-Patchwork-Id: 10556473 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 40F8714E2 for ; Mon, 6 Aug 2018 04:51:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 21F8F28FFB for ; Mon, 6 Aug 2018 04:51:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 139E529006; Mon, 6 Aug 2018 04:51:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6588A28FFB for ; Mon, 6 Aug 2018 04:51:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726672AbeHFG6l (ORCPT ); Mon, 6 Aug 2018 02:58:41 -0400 Received: from smtp.infotech.no ([82.134.31.41]:35000 "EHLO smtp.infotech.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726276AbeHFG6l (ORCPT ); Mon, 6 Aug 2018 02:58:41 -0400 Received: from localhost (localhost [127.0.0.1]) by smtp.infotech.no (Postfix) with ESMTP id 7724220424C; Mon, 6 Aug 2018 06:51:22 +0200 (CEST) X-Virus-Scanned: by amavisd-new-2.6.6 (20110518) (Debian) at infotech.no Received: from smtp.infotech.no ([127.0.0.1]) by localhost (smtp.infotech.no [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 36wg8dBG1tzM; Mon, 6 Aug 2018 06:51:20 +0200 (CEST) Received: from xtwo70.bingwo.ca (host-45-58-245-67.dyn.295.ca [45.58.245.67]) by smtp.infotech.no (Postfix) with ESMTPA id B9E3320423B; Mon, 6 Aug 2018 06:51:19 +0200 (CEST) From: Douglas Gilbert To: linux-scsi@vger.kernel.org Cc: martin.petersen@oracle.com, hare@suse.de, bart.vanassche@wdc.com, jthumshirn@suse.de Subject: [RFC PATCH 1/5] add tweakable bounds_check flag, now off by default Date: Mon, 6 Aug 2018 00:51:11 -0400 Message-Id: <20180806045115.7725-2-dgilbert@interlog.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180806045115.7725-1-dgilbert@interlog.com> References: <20180806045115.7725-1-dgilbert@interlog.com> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add bounds_check "rw" attribute to the sd driver. It controls whether each read/write operation submission does an "out of range" bounds check and a LBA/number_of_blocks alignment bounds check. The mainline kernel currently does both these checks. This patch changes that default to bounds_check=false, that is: the two checks are not done. SBC, SBC-2, SBC-3 and draft SBC-4 are require a device server (i.e. a SCSI disk) to fail any media command in which the LBA+number_of_blocks exceeds the capacity of the disk. So why should the sd driver also check it, given the block layer generated the request and knows the disk capacity and the disk itself also checks it? The block layer does almost all its block handling in units of 512 byte blocks whereas SCSI disks may have other logical block sizes (e.g. 4096 byte logical blocks). So when the block sizes are different it is possible that there is an alignment issue. But if that occurs, it would be a logic issue in the block layer. Note that the current mainline code does this check even when it is not needed (e.g. when the logical block size of the disk is 512 bytes). Signed-off-by: Douglas Gilbert --- Should a mechanism be added so this could set/cleared by: - a LLD for all disks it controls - kernel boot time parameter? drivers/scsi/sd.c | 55 +++++++++++++++++++++++++++++++++++++---------- drivers/scsi/sd.h | 1 + 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d1d08f039bdd..b17b8c66881d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -522,6 +522,32 @@ max_write_same_blocks_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(max_write_same_blocks); +static ssize_t +bounds_check_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + return sprintf(buf, "%u\n", sdkp->bounds_check); +} + +static ssize_t +bounds_check_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + int err, n; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + err = kstrtoint(buf, 10, &n); + if (!err) + sdkp->bounds_check = !!n; + + return err ? err : count; +} +static DEVICE_ATTR_RW(bounds_check); + static struct attribute *sd_disk_attrs[] = { &dev_attr_cache_type.attr, &dev_attr_FUA.attr, @@ -535,6 +561,7 @@ static struct attribute *sd_disk_attrs[] = { &dev_attr_zeroing_mode.attr, &dev_attr_max_write_same_blocks.attr, &dev_attr_max_medium_access_timeouts.attr, + &dev_attr_bounds_check.attr, NULL, }; ATTRIBUTE_GROUPS(sd_disk); @@ -1088,7 +1115,6 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); sector_t lba = sectors_to_logical(sdp, blk_rq_pos(rq)); unsigned int nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); - unsigned int mask = logical_to_sectors(sdp, 1) - 1; unsigned char protect, fua; bool write = rq_data_dir(rq) == WRITE; bool dif, dix; @@ -1106,17 +1132,24 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) goto out; } - if (unlikely(blk_rq_pos(rq) + blk_rq_sectors(rq) - > logical_to_sectors(sdp, sdkp->capacity))) { - scmd_printk(KERN_ERR, cmd, "access beyond end of device\n"); - ret = BLKPREP_KILL; - goto out; - } + if (sdkp->bounds_check) { + unsigned int mask = logical_to_sectors(sdp, 1) - 1; - if (unlikely((blk_rq_pos(rq) & mask) || (blk_rq_sectors(rq) & mask))) { - scmd_printk(KERN_ERR, cmd, "request not aligned to the logical block size\n"); - ret = BLKPREP_KILL; - goto out; + if (unlikely(blk_rq_pos(rq) + blk_rq_sectors(rq) + > logical_to_sectors(sdp, sdkp->capacity))) { + scmd_printk(KERN_ERR, cmd, + "access beyond end of device\n"); + ret = BLKPREP_KILL; + goto out; + } + + if (unlikely((blk_rq_pos(rq) & mask) || + (blk_rq_sectors(rq) & mask))) { + scmd_printk(KERN_ERR, cmd, + "request not aligned to logical block size\n"); + ret = BLKPREP_KILL; + goto out; + } } /* diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 392c7d078ae3..6f58d130fb75 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -117,6 +117,7 @@ struct scsi_disk { unsigned urswrz : 1; unsigned security : 1; unsigned ignore_medium_access_errors : 1; + unsigned bounds_check : 1; }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)