From patchwork Thu Oct 11 07:09:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 10636161 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 EC78869B1 for ; Thu, 11 Oct 2018 07:09:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D56272AED2 for ; Thu, 11 Oct 2018 07:09:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CA0422AEFF; Thu, 11 Oct 2018 07:09:58 +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.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable 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 36B102AED2 for ; Thu, 11 Oct 2018 07:09:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726714AbeJKOfw (ORCPT ); Thu, 11 Oct 2018 10:35:52 -0400 Received: from esa1.hgst.iphmx.com ([68.232.141.245]:12787 "EHLO esa1.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725995AbeJKOfw (ORCPT ); Thu, 11 Oct 2018 10:35:52 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1539241797; x=1570777797; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=KHdIYgKXpwd52OykaL0UelcBx5/jawRCZ2GZum5hFkM=; b=I37dVVrb7ZRZys+ph5k/7iIzgH7UhGFSFz2SLUhg2531KbxCcA9s4z6x 3KqSOAZo+gnKt/bXZrUytQecV8EATTGVpfF26FsFWSOi/zVQafgiGcRFx vU0HjWmn4sXV91Yf0jNecXP/ECQAMsu4MRg8tAg0r/RuNsyzhyfMS0P5M vtAHmyLudfBM4hOagzea/ui+uLXAl0TyQhr6uXqbB6Z6S5epz/kPI9cAC ZFby0NUNvYJdNjawBSqzt89IA3lkzyihsfBAomgG/PV+P6gb5r7I4Eqlb o6QfKbs3ShwXOrR7PJpbV9cFoDzl63C/jO+Y0yQcwE7V1fAdBB3rBvZQM w==; X-IronPort-AV: E=Sophos;i="5.54,367,1534780800"; d="scan'208";a="196047554" Received: from h199-255-45-15.hgst.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 11 Oct 2018 15:09:56 +0800 Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP; 10 Oct 2018 23:54:55 -0700 Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip02.wdc.com with ESMTP; 11 Oct 2018 00:09:56 -0700 From: Damien Le Moal To: linux-block@vger.kernel.org, Jens Axboe , linux-scsi@vger.kernel.org, "Martin K . Petersen" , dm-devel@redhat.com, Mike Snitzer Cc: Christoph Hellwig , Matias Bjorling Subject: [PATCH v2 02/11] scsi: sd_zbc: Reduce boot device scan and revalidate time Date: Thu, 11 Oct 2018 16:09:43 +0900 Message-Id: <20181011070952.13248-3-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181011070952.13248-1-damien.lemoal@wdc.com> References: <20181011070952.13248-1-damien.lemoal@wdc.com> Sender: linux-block-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Handling checks of ZBC device capacity using the max_lba field of the REPORT ZONES command reply for disks with rc_basis == 0 can be done using the same report zones command reply used to check the "same" field. Avoid executing a report zones command solely to check the disk capacity by merging sd_zbc_check_capacity() into sd_zbc_check_zone_size() and renaming that function to sd_zbc_check_zones(). This removes a costly execution of a full report zones command and so reduces device scan duration at boot time as well as the duration of disk revalidate calls. Furthermore, setting the partial report bit in the REPORT ZONES command cdb can significantly reduce this command execution time as the device does not have to count and report the total number of zones that could be reported assuming a large enough reply buffer. A non-partial zone report is necessary only for the first execution of report zones used to check the same field value (to ensure that this value applies to all zones of the disk). All other calls to sd_zbc_report_zones() can use a partial report to reduce execution time. Using a 14 TB ZBC disk, these simple changes reduce device scan time at boot from about 3.5s down to about 900ms. Disk revalidate times are also reduced from about 450ms down to 230ms. Signed-off-by: Damien Le Moal Reviewed-by: Christoph Hellwig --- drivers/scsi/sd_zbc.c | 94 ++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 54 deletions(-) diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 0b7d8787f785..ca73c46931c0 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -67,11 +67,17 @@ static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf, * @buf: Buffer to use for the reply * @buflen: the buffer size * @lba: Start LBA of the report + * @partial: Do partial report * * For internal use during device validation. + * Using partial=true can significantly speed up execution of a report zones + * command because the disk does not have to count all possible report matching + * zones and will only report the count of zones fitting in the command reply + * buffer. */ static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf, - unsigned int buflen, sector_t lba) + unsigned int buflen, sector_t lba, + bool partial) { struct scsi_device *sdp = sdkp->device; const int timeout = sdp->request_queue->rq_timeout; @@ -85,6 +91,8 @@ static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf, cmd[1] = ZI_REPORT_ZONES; put_unaligned_be64(lba, &cmd[2]); put_unaligned_be32(buflen, &cmd[10]); + if (partial) + cmd[14] = ZBC_REPORT_ZONE_PARTIAL; memset(buf, 0, buflen); result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, @@ -350,60 +358,25 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, return 0; } -/** - * sd_zbc_check_capacity - Check reported capacity. - * @sdkp: Target disk - * @buf: Buffer to use for commands - * - * ZBC drive may report only the capacity of the first conventional zones at - * LBA 0. This is indicated by the RC_BASIS field of the read capacity reply. - * Check this here. If the disk reported only its conventional zones capacity, - * get the total capacity by doing a report zones. - */ -static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf) -{ - sector_t lba; - int ret; - - if (sdkp->rc_basis != 0) - return 0; - - /* Do a report zone to get the maximum LBA to check capacity */ - ret = sd_zbc_report_zones(sdkp, buf, SD_BUF_SIZE, 0); - if (ret) - return ret; - - /* The max_lba field is the capacity of this device */ - lba = get_unaligned_be64(&buf[8]); - if (lba + 1 == sdkp->capacity) - return 0; - - if (sdkp->first_scan) - sd_printk(KERN_WARNING, sdkp, - "Changing capacity from %llu to max LBA+1 %llu\n", - (unsigned long long)sdkp->capacity, - (unsigned long long)lba + 1); - sdkp->capacity = lba + 1; - - return 0; -} - #define SD_ZBC_BUF_SIZE 131072U /** - * sd_zbc_check_zone_size - Check the device zone sizes + * sd_zbc_check_zones - Check the device capacity and 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. + * Check that the device capacity as reported by READ CAPACITY matches the + * max_lba value (plus one)of the report zones command reply. Also check that + * all zones of the device have an equal size, only allowing the last zone of + * the disk to have a smaller size (runt zone). The zone size must also be a + * power of two. * * Returns the zone size in number of blocks upon success or an error code * upon failure. */ -static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) +static s64 sd_zbc_check_zones(struct scsi_disk *sdkp) { u64 zone_blocks = 0; - sector_t block = 0; + sector_t max_lba, block = 0; unsigned char *buf; unsigned char *rec; unsigned int buf_len; @@ -416,11 +389,28 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) if (!buf) return -ENOMEM; - /* Do a report zone to get the same field */ - ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0); + /* Do a report zone to get max_lba and the same field */ + ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false); if (ret) goto out_free; + if (sdkp->rc_basis == 0) { + /* The max_lba field is the capacity of this device */ + max_lba = get_unaligned_be64(&buf[8]); + if (sdkp->capacity != max_lba + 1) { + if (sdkp->first_scan) + sd_printk(KERN_WARNING, sdkp, + "Changing capacity from %llu to max LBA+1 %llu\n", + (unsigned long long)sdkp->capacity, + (unsigned long long)max_lba + 1); + sdkp->capacity = max_lba + 1; + } + } + + /* + * Check same field: for any value other than 0, we know that all zones + * have the same size. + */ same = buf[4] & 0x0f; if (same > 0) { rec = &buf[64]; @@ -458,7 +448,7 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) if (block < sdkp->capacity) { ret = sd_zbc_report_zones(sdkp, buf, - SD_ZBC_BUF_SIZE, block); + SD_ZBC_BUF_SIZE, block, true); if (ret) goto out_free; } @@ -574,7 +564,8 @@ sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp, u32 zone_shift, goto out; while (lba < sdkp->capacity) { - ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, lba); + ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, + lba, true); if (ret) goto out; lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE, @@ -692,16 +683,11 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) if (ret) goto err; - /* Check capacity */ - ret = sd_zbc_check_capacity(sdkp, buf); - if (ret) - goto err; - /* * Check zone size: only devices with a constant zone size (except * an eventual last runt zone) that is a power of 2 are supported. */ - zone_blocks = sd_zbc_check_zone_size(sdkp); + zone_blocks = sd_zbc_check_zones(sdkp); ret = -EFBIG; if (zone_blocks != (u32)zone_blocks) goto err;