Received: by 2002:a05:6358:5282:b0:b5:90e7:25cb with SMTP id g2csp3803239rwa; Tue, 23 Aug 2022 10:20:06 -0700 (PDT) X-Google-Smtp-Source: AA6agR7iM2dOo9ZQAyi83KGbKtC7jvm3U6A5C8n3URz77ceq0NL+iOL1Y6+OROzyQQYvvS/RvmPB X-Received: by 2002:a17:903:2049:b0:172:eb95:c61e with SMTP id q9-20020a170903204900b00172eb95c61emr9941328pla.74.1661275206362; Tue, 23 Aug 2022 10:20:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1661275206; cv=none; d=google.com; s=arc-20160816; b=C2c9urDr+rtDWfY9wcxrxKArlWyBc+K8cQ6+5w+q5cYlOS8Gr7yKzCrwdummsyGwCF Gnryt4Rhu+C9pSXdBja8B2ji0D6ZC2q0VmO6VbJiEzU4JZ/Kf9rxRUy88kzDYUogxbyz 8v0VZEVWNuBBUGXVF7D2GZAepHn3RvdMkTxDBWz3Hm6gWVbjktRgU+0BlokDe3kbJ8ug j2LwsYkc3i7Z+PSipb3f6NBoQhBnNCOEHpDq7hNcJ2VlUVKficrhdI3S1PlvYxIReM8V DElz2aAOxpmf7y9m+vdMfkTIuYeJQQB8v5KnWKntE0U6vVBT6puo5OwrwH9pS8bjA5Or y0fA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:cc:to:from :subject:organization:dkim-signature; bh=XXAzfA+fOYtv11LNMO9ob47ffQq5WUBN0kv6KdmFv7Q=; b=XK72ln0ijBPuIhfZtYjZxoYQYE7ezK7irTUiw3aY4n2KeLKjbycn27eDhbZQA7FE0V 7i+ig52J27LpBCETsnHNM7PVBe/bLiVDKwKcbuHyXDAMutciKYPZ9kxXlbJJa470Fny2 zTWpa5NigqcwIrWUjZu4Yzzr0BmJYJglKqVADOnDuH3UwUpNNGwTJ6QyPq/NdVLoU8Nw Rh7Ub0Jl1avvwfoWeDk6aiqI4XERjd0sdldU56hGYULpv5PHK1llYJIm645X1BuUiVfO C7uI0tu2CMVSdMJxKrukleUeee0hNQdV0w7uW3V070q1vU2pc4rseAtEnVrM200F/o2z DF0g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=Hr5fVFN8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id k7-20020a170902c40700b0016d09df65d8si17204850plk.411.2022.08.23.10.19.55; Tue, 23 Aug 2022 10:20:06 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=Hr5fVFN8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343643AbiHWRBf (ORCPT + 99 others); Tue, 23 Aug 2022 13:01:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35690 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343957AbiHWRAk (ORCPT ); Tue, 23 Aug 2022 13:00:40 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 35EA2A2A8F for ; Tue, 23 Aug 2022 07:12:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1661263942; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XXAzfA+fOYtv11LNMO9ob47ffQq5WUBN0kv6KdmFv7Q=; b=Hr5fVFN87TtsCqQoC0uBAq6OYYOWzyLDbuMh3FjCF0TdcCrP8RUhT3uHI8Wh2VzIE3bQGp tZh84Fti4LEWtS9IhRcM3Y9gQA74KBWU01G44DCP9zZCvsiRcPex8blg74LqE/VHFPq+t0 mcmXlPdFmHmRe39vhV3vp0LGZFI62Rs= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-91-O7HXFN1wPZO0QXKkMJ5rJA-1; Tue, 23 Aug 2022 10:12:17 -0400 X-MC-Unique: O7HXFN1wPZO0QXKkMJ5rJA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id CDF08101A56D; Tue, 23 Aug 2022 14:12:15 +0000 (UTC) Received: from warthog.procyon.org.uk (unknown [10.33.36.72]) by smtp.corp.redhat.com (Postfix) with ESMTP id ACA2D1121315; Tue, 23 Aug 2022 14:12:14 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 1/7] iov_iter: Add a function to extract an iter's buffers to a bvec iter From: David Howells To: Steve French , Al Viro Cc: dhowells@redhat.com, Shyam Prasad N , Rohith Surabattula , Jeff Layton , linux-cifs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Date: Tue, 23 Aug 2022 15:12:14 +0100 Message-ID: <166126393409.708021.16165278011941496946.stgit@warthog.procyon.org.uk> In-Reply-To: <166126392703.708021.14465850073772688008.stgit@warthog.procyon.org.uk> References: <166126392703.708021.14465850073772688008.stgit@warthog.procyon.org.uk> User-Agent: StGit/1.5 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Copy cifs's setup_aio_ctx_iter() and to lib/iov_iter.c and generalise it as extract_iter_to_iter(). This allocates and sets up an array of bio_vecs for all the page fragments in an I/O iterator and sets a second supplied iterator to bvec-type pointing to the array. This is can be used when setting up for a direct I/O or an asynchronous I/O to set up a record of the page fragments that are going to contribute to the buffer, paging them all in to prevent DIO->mmap loops and allowing the original iterator to be deallocated (it may be on the stack of the caller). Note that extract_iter_to_iter() doesn't actually need to make a separate allocation for the page array. It can place the page array at the end of the bvec array storage, provided it traverses both arrays from the 0th element forwards. Signed-off-by: David Howells --- include/linux/uio.h | 4 ++ lib/iov_iter.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/include/linux/uio.h b/include/linux/uio.h index 5896af36199c..88fd93508710 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -251,6 +251,10 @@ ssize_t iov_iter_get_pages2(struct iov_iter *i, struct page **pages, size_t maxsize, unsigned maxpages, size_t *start); ssize_t iov_iter_get_pages_alloc2(struct iov_iter *i, struct page ***pages, size_t maxsize, size_t *start); +ssize_t extract_iter_to_iter(struct iov_iter *orig, + size_t orig_len, + struct iov_iter *new, + struct bio_vec **_bv); int iov_iter_npages(const struct iov_iter *i, int maxpages); void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state); diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 4b7fce72e3e5..c07bf978b935 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1518,6 +1518,99 @@ ssize_t iov_iter_get_pages_alloc2(struct iov_iter *i, } EXPORT_SYMBOL(iov_iter_get_pages_alloc2); +/** + * extract_iter_to_iter - Extract the pages from one iterator into another + * @orig: The original iterator + * @orig_len: The amount of iterator to copy + * @new: The iterator to be set up + * @_bv: Where to store the allocated bvec table pointer, if allocated + * + * Extract the page fragments from the given amount of the source iterator and + * build up a second iterator that refers to all of those bits. This allows + * the original iterator to disposed of. + * + * If a bvec array is created, the number of pages in the array is returned and + * a pointer to the array is saved into *@_bv; + */ +ssize_t extract_iter_to_iter(struct iov_iter *orig, + size_t orig_len, + struct iov_iter *new, + struct bio_vec **_bv) +{ + struct bio_vec *bv = NULL; + struct page **pages; + unsigned int cur_npages; + unsigned int max_pages = iov_iter_npages(orig, INT_MAX); + unsigned int npages = 0; + unsigned int i; + size_t count = orig_len; + ssize_t ret; + size_t bv_size, pg_size; + size_t start; + size_t len; + + *_bv = NULL; + + if (iov_iter_is_kvec(orig) || iov_iter_is_discard(orig)) { + *new = *orig; + iov_iter_advance(orig, count); + return 0; + } + + bv_size = array_size(max_pages, sizeof(*bv)); + bv = kvmalloc(bv_size, GFP_KERNEL); + if (!bv) + return -ENOMEM; + + /* Put the page list at the end of the bvec list storage. bvec + * elements are larger than page pointers, so as long as we work + * 0->last, we should be fine. + */ + pg_size = array_size(max_pages, sizeof(*pages)); + pages = (void *)bv + bv_size - pg_size; + + while (count && npages < max_pages) { + ret = iov_iter_get_pages2(orig, pages, count, max_pages - npages, + &start); + if (ret < 0) { + pr_err("Couldn't get user pages (rc=%zd)\n", ret); + break; + } + + if (ret > count) { + pr_err("get_pages rc=%zd more than %zu\n", ret, count); + break; + } + + iov_iter_advance(orig, ret); + count -= ret; + ret += start; + cur_npages = DIV_ROUND_UP(ret, PAGE_SIZE); + + if (npages + cur_npages > max_pages) { + pr_err("Out of bvec array capacity (%u vs %u)\n", + npages + cur_npages, max_pages); + break; + } + + for (i = 0; i < cur_npages; i++) { + len = ret > PAGE_SIZE ? PAGE_SIZE : ret; + bv[npages + i].bv_page = *pages++; + bv[npages + i].bv_offset = start; + bv[npages + i].bv_len = len - start; + ret -= len; + start = 0; + } + + npages += cur_npages; + } + + *_bv = bv; + iov_iter_bvec(new, iov_iter_rw(orig), bv, npages, orig_len - count); + return npages; +} +EXPORT_SYMBOL(extract_iter_to_iter); + size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i) {