From patchwork Wed Jun 26 01:47:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11016733 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 2C8411908 for ; Wed, 26 Jun 2019 01:48:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1D8892859F for ; Wed, 26 Jun 2019 01:48:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 11C2A28623; Wed, 26 Jun 2019 01:48:05 +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=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 A96542859F for ; Wed, 26 Jun 2019 01:48:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726374AbfFZBsE (ORCPT ); Tue, 25 Jun 2019 21:48:04 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:15693 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726304AbfFZBsD (ORCPT ); Tue, 25 Jun 2019 21:48:03 -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=1561513684; x=1593049684; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=/B+Zmi2zc/HDhqm84fUS/9k0x548ev4KQjTeX4Nu7jw=; b=CpzzV1NuMZgaN+62vQ397SJT9TwhZULXEUjy2NN89uI0NEi0sK3J4L0k dcJ8fAbNAUXBtkdTfCrEvF6fP9a/xFxxjQxCOauJZ0L5U+W32iTUavxEy w20nfwlodBkq0wRRHnQPt4OCqfwaxuNTNOhWn3erpuaaBoDyNXqL58txa DzUXb4bHwr7ABfW2cEYed0Hov3q2PTNra6ifxU+gO89AZlpBfN2WVcyW3 XAROI+oXMDiSIDdDaaOk4+k/Wb+rH1JQCvZ2Wx4YLMWQ6UWsFZWwnoY0i LYscX1qf91DoUqaUxwWBEL6olbt2mEaJ9bvJYJ+GOOzLFnk1v7kQXYy5x w==; X-IronPort-AV: E=Sophos;i="5.63,418,1557158400"; d="scan'208";a="116422525" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 26 Jun 2019 09:48:03 +0800 IronPort-SDR: 0cSChulNqOn6BNfU8nEWCUdm88MmG3Ns5J0Il/qT8Qosb8DMh8gU83MWBrm0DiZ8iCuBGoB3F6 loAiKewXLV9toUYgU2qA/dYe280RopEu5ECe6k8bKhhv2gG4dvB2pzIupmh9ofl5NBBHDeeqIm eS28nO+srpacS7v1j3CEjDifuTVjAX7pX/D+sq0CD2ORCXF189kFdtaxi1Tq3voi6TncqmjVIO EPch+miGdkPVatHXTYrPfy7Tj3itrrz4qA+JMnXRlCzqf8Ki66J5fvpMxsHfBr210gKDLbTPVl gNqKjKHZyBN+l943V/Um+XbC Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep01.wdc.com with ESMTP; 25 Jun 2019 18:47:12 -0700 IronPort-SDR: WDidXsHmYvzTMG7hN8S5ZVTY7o5ENppZIv+CLVZLt0BT2osrRg2NfDHuZV5uG674/U6otglYcZ 2VqbN4Xo+tJ8CPnOrKsQtopCquJ4La+Cw8KXzCwVBvAphxo/u0Xws+Fx/rMZjMHXdculL/KeTN kBd0UGTkvGZdvzbbh8l1JTsJuDnhmMm8wKglEVm6K9HjHpkpmrk3JDf5ZxWo3YQpziyiCDDoyS corgGmgAN5UJIjuhvwK5OU6BOblaYdTbjP2HUZXHZ/iU1p8DtYC14DIMvUJCqyidpcgbsQBsin IT8= Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip02.wdc.com with ESMTP; 25 Jun 2019 18:48:01 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" , linux-block@vger.kernel.org, Jens Axboe Cc: Christoph Hellwig , Bart Van Assche Subject: [PATCH V2 1/3] block: Allow mapping of vmalloc-ed buffers Date: Wed, 26 Jun 2019 10:47:57 +0900 Message-Id: <20190626014759.15285-2-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190626014759.15285-1-damien.lemoal@wdc.com> References: <20190626014759.15285-1-damien.lemoal@wdc.com> MIME-Version: 1.0 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 To allow the SCSI subsystem scsi_execute_req() function to issue requests using large buffers that are better allocated with vmalloc() rather than kmalloc(), modify bio_map_kern() to allow passing a buffer allocated with the vmalloc() function. To do so, simply test the buffer address using is_vmalloc_addr() and use vmalloc_to_page() instead of virt_to_page() to obtain the pages of vmalloc-ed buffers. Fixes: 515ce6061312 ("scsi: sd_zbc: Fix sd_zbc_report_zones() buffer allocation") Fixes: e76239a3748c ("block: add a report_zones method") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal --- block/bio.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/block/bio.c b/block/bio.c index ce797d73bb43..46e0b970e287 100644 --- a/block/bio.c +++ b/block/bio.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "blk.h" @@ -1501,9 +1502,14 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len, unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; unsigned long start = kaddr >> PAGE_SHIFT; const int nr_pages = end - start; + bool is_vmalloc = is_vmalloc_addr(data); + struct page *page; int offset, i; struct bio *bio; + if (is_vmalloc) + invalidate_kernel_vmap_range(data, len); + bio = bio_kmalloc(gfp_mask, nr_pages); if (!bio) return ERR_PTR(-ENOMEM); @@ -1518,7 +1524,11 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len, if (bytes > len) bytes = len; - if (bio_add_pc_page(q, bio, virt_to_page(data), bytes, + if (is_vmalloc) + page = vmalloc_to_page(data); + else + page = virt_to_page(data); + if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) { /* we don't support partial mappings */ bio_put(bio); From patchwork Wed Jun 26 01:47:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11016737 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 5566B924 for ; Wed, 26 Jun 2019 01:48:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 452162859F for ; Wed, 26 Jun 2019 01:48:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 399AC28623; Wed, 26 Jun 2019 01:48:06 +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=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 79B832859F for ; Wed, 26 Jun 2019 01:48:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726304AbfFZBsE (ORCPT ); Tue, 25 Jun 2019 21:48:04 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:15693 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726037AbfFZBsE (ORCPT ); Tue, 25 Jun 2019 21:48:04 -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=1561513684; x=1593049684; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=hfnOxqqnyea5FT+2FpWuq0wjXhpxLdHN1IJgQUBnGWQ=; b=qWYtrnKHv6o5Bu2s8Dfr0XVdnFEdJCcCp+j3kNfTfAvA3RtncwovzIpP j1+ANufNtF/fr8PN6qMBKipN7MgJnc0boI+MFQx89CjCAzQHvQXMNE5xx fTZStv9fyzp2reYqsa4uQp/3wArxH76GuG5oeY2O4b7ah0DTKYNK3dh69 EtIDjR01pdn5cbPS/VHcP8m4I+mVaZAGNyKcGB1MpB138RGKkp4tQJz97 8tKLAqfF3abTU7Kb1oh+xbMGKdgx446q+eAs+M2cKxhLoFRUT2GOoVI7u ham9GI/fdjI//x77/t3z86/nMHoXCrOSBJl93wUm17uS2ERWUCaTr7OS5 w==; X-IronPort-AV: E=Sophos;i="5.63,418,1557158400"; d="scan'208";a="116422527" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 26 Jun 2019 09:48:04 +0800 IronPort-SDR: MkxmpOPsNGKc/xX0qhXYZBG8VMUiiiwjWU4PPTKsMvRUQI+23OHssZj99lOUCNLfh4N6+Z4YfO HKlVzqoMajdAWCdtuyu+LTJ4AsGJJtl4LqWEFud4qG9g5ookf8rcKqux0TkvrrhZ4CZL8FwVvB iJU0XelF2IiR4tBefRlHhX4jyKaH+UQzl/pVCW+B1Gs0ZRiDWmC4dnXmoFUPTqxpLEZTacUZSs rBdsJI3Qk90IigHX8Oj6LR6QF1UEnHW+Se9DBo0nwvmfuzZpEBI6Ovj6yLqeAtnQJW6ZiPVPpW z4kBE+qIYz2tqfQvZWnTCE9b Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep01.wdc.com with ESMTP; 25 Jun 2019 18:47:13 -0700 IronPort-SDR: k+atv8lUOwJJ0JuNHjltrebr5zpqjCP3g/Pb81tMc3Pdrz7uwLYoQ2sFKaR4QZGzv4xuFe8SJ9 wq68+8bwEZD6XDAKhRXMq9H61QTttpfOe5HvK4nnWq1jzwHwMXAQNHPTy0rft/sCDsWRqeZjHb RvoajwP91g+WA2PwqCN6WNGdTx3LJzIanR/AoLjTlGZOvFNI6WbJ77YzIvMSXmKHHXi3PdH6Cp OjhheQs60N+s6JIj7lwALrCKDXRM2LlctWNqiHqjcdvpH+VATURdfV6lS++/T5EFuHYaSzqSPn 9d0= Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip02.wdc.com with ESMTP; 25 Jun 2019 18:48:02 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" , linux-block@vger.kernel.org, Jens Axboe Cc: Christoph Hellwig , Bart Van Assche Subject: [PATCH V2 2/3] sd_zbc: Fix report zones buffer allocation Date: Wed, 26 Jun 2019 10:47:58 +0900 Message-Id: <20190626014759.15285-3-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190626014759.15285-1-damien.lemoal@wdc.com> References: <20190626014759.15285-1-damien.lemoal@wdc.com> MIME-Version: 1.0 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 During disk scan and revalidation done with sd_revalidate(), the zones of a zoned disk are checked using the helper function blk_revalidate_disk_zones() if a configuration change is detected (change in the number of zones or zone size). The function blk_revalidate_disk_zones() issues report_zones calls that are very large, that is, to obtain zone information for all zones of the disk with a single command. The size of the report zones command buffer necessary for such large request generally is lower than the disk max_hw_sectors and KMALLOC_MAX_SIZE (4MB) and succeeds on boot (no memory fragmentation), but often fail at run time (e.g. hot-plug event). This causes the disk revalidation to fail and the disk capacity to be changed to 0. This problem can be avoided by using vmalloc() instead of kmalloc() for the buffer allocation. To limit the amount of memory to be allocated, this patch also introduces the arbitrary SD_ZBC_REPORT_MAX_ZONES maximum number of zones to report with a single report zones command. This limit may be lowered further to satisfy the disk max_hw_sectors limit. Finally, to ensure that the vmalloc-ed buffer can always be mapped in a request, the buffer size is further limited to at most queue_max_segments() pages, allowing successful mapping of the buffer even in the worst case scenario where none of the buffer pages are contiguous. Fixes: 515ce6061312 ("scsi: sd_zbc: Fix sd_zbc_report_zones() buffer allocation") Fixes: e76239a3748c ("block: add a report_zones method") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal --- drivers/scsi/sd_zbc.c | 80 ++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 7334024b64f1..f1474732784c 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -9,6 +9,7 @@ */ #include +#include #include @@ -103,6 +104,48 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf, return 0; } +/* + * Maximum number of zones to get with one report zones command. + */ +#define SD_ZBC_REPORT_MAX_ZONES 8192U + +/** + * Allocate a buffer for report zones reply. + * @disk: The target disk + * @nr_zones: Maximum number of zones to report + * @buflen: Size of the buffer allocated + * @gfp_mask: Memory allocation mask + * + */ +static void *sd_zbc_alloc_report_buffer(struct request_queue *q, + unsigned int nr_zones, size_t *buflen, + gfp_t gfp_mask) +{ + size_t bufsize; + void *buf; + + /* + * Report zone buffer size should be at most 64B times the number of + * zones requested plus the 64B reply header, but should be at least + * SECTOR_SIZE for ATA devices. + * Make sure that this size does not exceed the hardware capabilities. + * Furthermore, since the report zone command cannot be split, make + * sure that the allocated buffer can always be mapped by limiting the + * number of pages allocated to the HBA max segments limit. + */ + nr_zones = min(nr_zones, SD_ZBC_REPORT_MAX_ZONES); + bufsize = roundup((nr_zones + 1) * 64, 512); + bufsize = min_t(size_t, bufsize, + queue_max_hw_sectors(q) << SECTOR_SHIFT); + bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT); + + buf = __vmalloc(bufsize, gfp_mask, PAGE_KERNEL); + if (buf) + *buflen = bufsize; + + return buf; +} + /** * sd_zbc_report_zones - Disk report zones operation. * @disk: The target disk @@ -118,9 +161,9 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, gfp_t gfp_mask) { struct scsi_disk *sdkp = scsi_disk(disk); - unsigned int i, buflen, nrz = *nr_zones; + unsigned int i, nrz = *nr_zones; unsigned char *buf; - size_t offset = 0; + size_t buflen = 0, offset = 0; int ret = 0; if (!sd_is_zoned(sdkp)) @@ -132,16 +175,14 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, * without exceeding the device maximum command size. For ATA disks, * buffers must be aligned to 512B. */ - buflen = min(queue_max_hw_sectors(disk->queue) << 9, - roundup((nrz + 1) * 64, 512)); - buf = kmalloc(buflen, gfp_mask); + buf = sd_zbc_alloc_report_buffer(disk->queue, nrz, &buflen, gfp_mask); if (!buf) return -ENOMEM; ret = sd_zbc_do_report_zones(sdkp, buf, buflen, sectors_to_logical(sdkp->device, sector), true); if (ret) - goto out_free_buf; + goto out; nrz = min(nrz, get_unaligned_be32(&buf[0]) / 64); for (i = 0; i < nrz; i++) { @@ -152,8 +193,8 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, *nr_zones = nrz; -out_free_buf: - kfree(buf); +out: + kvfree(buf); return ret; } @@ -287,8 +328,6 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, return 0; } -#define SD_ZBC_BUF_SIZE 131072U - /** * sd_zbc_check_zones - Check the device capacity and zone sizes * @sdkp: Target disk @@ -304,22 +343,23 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, */ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) { + size_t bufsize, buflen; u64 zone_blocks = 0; sector_t max_lba, block = 0; unsigned char *buf; unsigned char *rec; - unsigned int buf_len; - unsigned int list_length; int ret; u8 same; /* Get a buffer */ - buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); + buf = sd_zbc_alloc_report_buffer(sdkp->disk->queue, + SD_ZBC_REPORT_MAX_ZONES, + &bufsize, GFP_NOIO); if (!buf) return -ENOMEM; /* Do a report zone to get max_lba and the same field */ - ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false); + ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, 0, false); if (ret) goto out_free; @@ -355,12 +395,12 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) do { /* Parse REPORT ZONES header */ - list_length = get_unaligned_be32(&buf[0]) + 64; + buflen = min_t(size_t, get_unaligned_be32(&buf[0]) + 64, + bufsize); rec = buf + 64; - buf_len = min(list_length, SD_ZBC_BUF_SIZE); /* Parse zone descriptors */ - while (rec < buf + buf_len) { + while (rec < buf + buflen) { u64 this_zone_blocks = get_unaligned_be64(&rec[8]); if (zone_blocks == 0) { @@ -376,8 +416,8 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) } if (block < sdkp->capacity) { - ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, - block, true); + ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, block, + true); if (ret) goto out_free; } @@ -408,7 +448,7 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) } out_free: - kfree(buf); + kvfree(buf); return ret; } From patchwork Wed Jun 26 01:47:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11016741 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 57E28924 for ; Wed, 26 Jun 2019 01:48:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4849E2859F for ; Wed, 26 Jun 2019 01:48:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3D0BC28623; Wed, 26 Jun 2019 01:48:07 +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=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 C9A1E2859F for ; Wed, 26 Jun 2019 01:48:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726037AbfFZBsG (ORCPT ); Tue, 25 Jun 2019 21:48:06 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:15693 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726401AbfFZBsF (ORCPT ); Tue, 25 Jun 2019 21:48:05 -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=1561513685; x=1593049685; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=lg8pbEXqIGRxgTLVtp82Eq91m5uzXzwMVXBnCRVLznI=; b=aQi5wADhiDEtCJ3BHRVBpBE9Lq+sEDSZTwzUI2xP55f5i68X4T+lZ+cC Z9CRBaxeSmS9O/CxnAqggbJ84h3M3EqLH5KRAgiCZB3rR36iHOWMC7Xcy B/7EGe2BdsLCr0RkSZJj8tUbwVshYuofdMU2l/2/aBNRcFFIF2uX5go8r 076ERCt0RqeGaS2bUiEUjHIBQy1lL90x6U7mXlhUvgCfiFRXFtr2d+eC5 dj21VT3dLH1dYcJvG9oSM/u11h3WmTIIkTW6ypBY5tbe86WUa0nDW4p23 SdCSQxkoGJmpyubKHFwe3Zne3LjnAkvyrfoAMIJxfrbRsV7YMM0NHDTJN g==; X-IronPort-AV: E=Sophos;i="5.63,418,1557158400"; d="scan'208";a="116422529" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 26 Jun 2019 09:48:05 +0800 IronPort-SDR: qOTpe0DgvT2kbr4ZRc65rQ/WV56GJ4qjw4c1z2Np58uNJpNj1GXBuTfbv1pRxg5iXd0BpI5y2J 9hm28/A7T/n59MGXgbqIHT1L3EIyX7CEtUtZvF6svLUehIS7Edg/Gcj2KimP1LwUDwPQu6isdP HX65Kf3bVk6Wvtubd8GHcEeUtK+LvMo6TP5kERry4rCorhL/mgHvRncpw8mApoD1upKUY2igb2 0nL6QC2zxE4RkteTK+WfDfkCpxr3RotmSqqXViVm+LSPyGKjoKLlm2JIfESn18V6Ho788lhJrU 8qhomkrIjm5HKNwB7zkWl4WQ Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep01.wdc.com with ESMTP; 25 Jun 2019 18:47:15 -0700 IronPort-SDR: H4nLPmYfq04J07ckE/4WlprUwtVMa0PVFo+Q4P6rLf3po4rMydwLksfkOQmiKuBQDhugAmisGH R9f6seEXxfEh1uJdcfV3dAw7G4ReMms/3XKAuanQs6UiR0wYzNeCB7uAuZT8d7aA8NTbdiFFNr 63YDb/rKnot4mNriGXn5bQTsACiiXwiIwsR5e0O/dnWmo6znvIexi6PMDAuUN/9SY+sIi4Nsgy p/pKagM/CJhpylikmnHf40Qg6fMgUtg34ePHfN8zk4nChpttv/c0MXC+hB6fw2sbttCBi9yCAP Iak= Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip02.wdc.com with ESMTP; 25 Jun 2019 18:48:03 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" , linux-block@vger.kernel.org, Jens Axboe Cc: Christoph Hellwig , Bart Van Assche Subject: [PATCH V2 3/3] block: Limit zone array allocation size Date: Wed, 26 Jun 2019 10:47:59 +0900 Message-Id: <20190626014759.15285-4-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190626014759.15285-1-damien.lemoal@wdc.com> References: <20190626014759.15285-1-damien.lemoal@wdc.com> MIME-Version: 1.0 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 Limit the size of the struct blk_zone array used in blk_revalidate_disk_zones() to avoid memory allocation failures leading to disk revalidation failure. Further reduce the likelyhood of these failures by using kvmalloc() instead of directly allocating contiguous pages. Fixes: 515ce6061312 ("scsi: sd_zbc: Fix sd_zbc_report_zones() buffer allocation") Fixes: e76239a3748c ("block: add a report_zones method") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Reviewed-by: Bart Van Assche --- block/blk-zoned.c | 29 +++++++++++++---------------- include/linux/blkdev.h | 5 +++++ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/block/blk-zoned.c b/block/blk-zoned.c index ae7e91bd0618..26f878b9b5f5 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -373,22 +373,20 @@ static inline unsigned long *blk_alloc_zone_bitmap(int node, * Allocate an array of struct blk_zone to get nr_zones zone information. * The allocated array may be smaller than nr_zones. */ -static struct blk_zone *blk_alloc_zones(int node, unsigned int *nr_zones) +static struct blk_zone *blk_alloc_zones(unsigned int *nr_zones) { - size_t size = *nr_zones * sizeof(struct blk_zone); - struct page *page; - int order; - - for (order = get_order(size); order >= 0; order--) { - page = alloc_pages_node(node, GFP_NOIO | __GFP_ZERO, order); - if (page) { - *nr_zones = min_t(unsigned int, *nr_zones, - (PAGE_SIZE << order) / sizeof(struct blk_zone)); - return page_address(page); - } + struct blk_zone *zones; + size_t nrz = min(*nr_zones, BLK_ZONED_REPORT_MAX_ZONES); + + zones = kvcalloc(nrz, sizeof(struct blk_zone), GFP_NOIO); + if (!zones) { + *nr_zones = 0; + return NULL; } - return NULL; + *nr_zones = nrz; + + return zones; } void blk_queue_free_zone_bitmaps(struct request_queue *q) @@ -443,7 +441,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk) /* Get zone information and initialize seq_zones_bitmap */ rep_nr_zones = nr_zones; - zones = blk_alloc_zones(q->node, &rep_nr_zones); + zones = blk_alloc_zones(&rep_nr_zones); if (!zones) goto out; @@ -480,8 +478,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk) blk_mq_unfreeze_queue(q); out: - free_pages((unsigned long)zones, - get_order(rep_nr_zones * sizeof(struct blk_zone))); + kvfree(zones); kfree(seq_zones_wlock); kfree(seq_zones_bitmap); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 592669bcc536..f7faac856017 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -344,6 +344,11 @@ struct queue_limits { #ifdef CONFIG_BLK_DEV_ZONED +/* + * Maximum number of zones to report with a single report zones command. + */ +#define BLK_ZONED_REPORT_MAX_ZONES 8192U + extern unsigned int blkdev_nr_zones(struct block_device *bdev); extern int blkdev_report_zones(struct block_device *bdev, sector_t sector, struct blk_zone *zones,