From patchwork Fri Sep 23 19:02:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Al Viro X-Patchwork-Id: 9348623 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 5FD80607D0 for ; Fri, 23 Sep 2016 19:03:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 49DF42AC39 for ; Fri, 23 Sep 2016 19:03:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3E4E42AD64; Fri, 23 Sep 2016 19:03:03 +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=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from oss.sgi.com (oss.sgi.com [192.48.182.195]) (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id A38182AC39 for ; Fri, 23 Sep 2016 19:03:02 +0000 (UTC) Received: from oss.sgi.com (localhost [IPv6:::1]) by oss.sgi.com (Postfix) with ESMTP id 07AE87CBD; Fri, 23 Sep 2016 14:03:02 -0500 (CDT) X-Original-To: xfs@oss.sgi.com Delivered-To: xfs@oss.sgi.com Received: from relay.sgi.com (relay2.corp.sgi.com [137.38.102.29]) by oss.sgi.com (Postfix) with ESMTP id 80AB97CBC for ; Fri, 23 Sep 2016 14:02:58 -0500 (CDT) Received: from cuda.sgi.com (cuda1.sgi.com [192.48.157.11]) by relay2.corp.sgi.com (Postfix) with ESMTP id 35BCF304043 for ; Fri, 23 Sep 2016 12:02:58 -0700 (PDT) X-ASG-Debug-ID: 1474657373-0bf8150b1133240001-NocioJ Received: from ZenIV.linux.org.uk (zeniv.linux.org.uk [195.92.253.2]) by cuda.sgi.com with ESMTP id AKTyc2oD5DBVUjmk (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Fri, 23 Sep 2016 12:02:54 -0700 (PDT) X-Barracuda-Envelope-From: viro@ftp.linux.org.uk X-Barracuda-Effective-Source-IP: zeniv.linux.org.uk[195.92.253.2] X-Barracuda-Apparent-Source-IP: 195.92.253.2 Received: from viro by ZenIV.linux.org.uk with local (Exim 4.86_2 #1 (Red Hat Linux)) id 1bnVkI-0007i1-DW; Fri, 23 Sep 2016 19:02:50 +0000 Date: Fri, 23 Sep 2016 20:02:50 +0100 From: Al Viro To: Linus Torvalds Subject: [PATCH 03/11] splice: switch get_iovec_page_array() to iov_iter Message-ID: <20160923190250.GA2356@ZenIV.linux.org.uk> X-ASG-Orig-Subj: [PATCH 03/11] splice: switch get_iovec_page_array() to iov_iter References: <20160909023452.GO2356@ZenIV.linux.org.uk> <20160909221945.GQ2356@ZenIV.linux.org.uk> <20160914031648.GB2356@ZenIV.linux.org.uk> <20160914042559.GC2356@ZenIV.linux.org.uk> <20160917082007.GA6489@ZenIV.linux.org.uk> <20160917190023.GA8039@ZenIV.linux.org.uk> <20160923190032.GA25771@ZenIV.linux.org.uk> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20160923190032.GA25771@ZenIV.linux.org.uk> User-Agent: Mutt/1.6.1 (2016-04-27) X-Barracuda-Connect: zeniv.linux.org.uk[195.92.253.2] X-Barracuda-Start-Time: 1474657374 X-Barracuda-Encrypted: ECDHE-RSA-AES256-GCM-SHA384 X-Barracuda-URL: https://192.48.157.11:443/cgi-mod/mark.cgi X-Barracuda-Scan-Msg-Size: 5236 X-Virus-Scanned: by bsmtpd at sgi.com X-Barracuda-BRTS-Status: 1 X-Barracuda-Spam-Score: 0.00 X-Barracuda-Spam-Status: No, SCORE=0.00 using per-user scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=2.7 tests=BSF_SC0_MISMATCH_TO X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.33164 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.00 BSF_SC0_MISMATCH_TO Envelope rcpt doesn't match header Cc: Jens Axboe , CAI Qian , Nick Piggin , xfs@oss.sgi.com, linux-xfs , linux-fsdevel@vger.kernel.org X-BeenThere: xfs@oss.sgi.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: XFS Filesystem from SGI List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: xfs-bounces@oss.sgi.com Sender: xfs-bounces@oss.sgi.com X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Al Viro --- fs/splice.c | 135 ++++++++++++++++-------------------------------------------- 1 file changed, 36 insertions(+), 99 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 36e9353..31c52e0 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1434,106 +1434,32 @@ static long do_splice(struct file *in, loff_t __user *off_in, return -EINVAL; } -/* - * Map an iov into an array of pages and offset/length tupples. With the - * partial_page structure, we can map several non-contiguous ranges into - * our ones pages[] map instead of splitting that operation into pieces. - * Could easily be exported as a generic helper for other users, in which - * case one would probably want to add a 'max_nr_pages' parameter as well. - */ -static int get_iovec_page_array(const struct iovec __user *iov, - unsigned int nr_vecs, struct page **pages, - struct partial_page *partial, bool aligned, +static int get_iovec_page_array(struct iov_iter *from, + struct page **pages, + struct partial_page *partial, unsigned int pipe_buffers) { - int buffers = 0, error = 0; - - while (nr_vecs) { - unsigned long off, npages; - struct iovec entry; - void __user *base; - size_t len; - int i; - - error = -EFAULT; - if (copy_from_user(&entry, iov, sizeof(entry))) - break; - - base = entry.iov_base; - len = entry.iov_len; - - /* - * Sanity check this iovec. 0 read succeeds. - */ - error = 0; - if (unlikely(!len)) - break; - error = -EFAULT; - if (!access_ok(VERIFY_READ, base, len)) - break; - - /* - * Get this base offset and number of pages, then map - * in the user pages. - */ - off = (unsigned long) base & ~PAGE_MASK; - - /* - * If asked for alignment, the offset must be zero and the - * length a multiple of the PAGE_SIZE. - */ - error = -EINVAL; - if (aligned && (off || len & ~PAGE_MASK)) - break; - - npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (npages > pipe_buffers - buffers) - npages = pipe_buffers - buffers; - - error = get_user_pages_fast((unsigned long)base, npages, - 0, &pages[buffers]); - - if (unlikely(error <= 0)) - break; - - /* - * Fill this contiguous range into the partial page map. - */ - for (i = 0; i < error; i++) { - const int plen = min_t(size_t, len, PAGE_SIZE - off); - - partial[buffers].offset = off; - partial[buffers].len = plen; - - off = 0; - len -= plen; + int buffers = 0; + while (iov_iter_count(from)) { + ssize_t copied; + size_t start; + + copied = iov_iter_get_pages(from, pages + buffers, ~0UL, + pipe_buffers - buffers, &start); + if (copied <= 0) + return buffers ? buffers : copied; + + iov_iter_advance(from, copied); + while (copied) { + int size = min_t(int, copied, PAGE_SIZE - start); + partial[buffers].offset = start; + partial[buffers].len = size; + copied -= size; + start = 0; buffers++; } - - /* - * We didn't complete this iov, stop here since it probably - * means we have to move some of this into a pipe to - * be able to continue. - */ - if (len) - break; - - /* - * Don't continue if we mapped fewer pages than we asked for, - * or if we mapped the max number of pages that we have - * room for. - */ - if (error < npages || buffers == pipe_buffers) - break; - - nr_vecs--; - iov++; } - - if (buffers) - return buffers; - - return error; + return buffers; } static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, @@ -1587,10 +1513,13 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov, * as splice-from-memory, where the regular splice is splice-from-file (or * to file). In both cases the output is a pipe, naturally. */ -static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, +static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov, unsigned long nr_segs, unsigned int flags) { struct pipe_inode_info *pipe; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov = iovstack; + struct iov_iter from; struct page *pages[PIPE_DEF_BUFFERS]; struct partial_page partial[PIPE_DEF_BUFFERS]; struct splice_pipe_desc spd = { @@ -1607,11 +1536,18 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, if (!pipe) return -EBADF; - if (splice_grow_spd(pipe, &spd)) + ret = import_iovec(WRITE, uiov, nr_segs, + ARRAY_SIZE(iovstack), &iov, &from); + if (ret < 0) + return ret; + + if (splice_grow_spd(pipe, &spd)) { + kfree(iov); return -ENOMEM; + } - spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages, - spd.partial, false, + spd.nr_pages = get_iovec_page_array(&from, spd.pages, + spd.partial, spd.nr_pages_max); if (spd.nr_pages <= 0) ret = spd.nr_pages; @@ -1619,6 +1555,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, ret = splice_to_pipe(pipe, &spd); splice_shrink_spd(&spd); + kfree(iov); return ret; }