From patchwork Fri Sep 23 19:04:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Al Viro X-Patchwork-Id: 9348637 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 121CB607D0 for ; Fri, 23 Sep 2016 19:04:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F1D132AC39 for ; Fri, 23 Sep 2016 19:04:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E60EC2AD64; Fri, 23 Sep 2016 19:04:36 +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=unavailable 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 521152AC39 for ; Fri, 23 Sep 2016 19:04:36 +0000 (UTC) Received: from oss.sgi.com (localhost [IPv6:::1]) by oss.sgi.com (Postfix) with ESMTP id A6C117CBD; Fri, 23 Sep 2016 14:04:35 -0500 (CDT) X-Original-To: xfs@oss.sgi.com Delivered-To: xfs@oss.sgi.com Received: from relay.sgi.com (relay3.corp.sgi.com [198.149.34.15]) by oss.sgi.com (Postfix) with ESMTP id 0A37F7CBC for ; Fri, 23 Sep 2016 14:04:33 -0500 (CDT) Received: from cuda.sgi.com (cuda3.sgi.com [192.48.176.15]) by relay3.corp.sgi.com (Postfix) with ESMTP id 72004AC002 for ; Fri, 23 Sep 2016 12:04:29 -0700 (PDT) X-ASG-Debug-ID: 1474657466-0bf57c18ca308f0001-NocioJ Received: from ZenIV.linux.org.uk (zeniv.linux.org.uk [195.92.253.2]) by cuda.sgi.com with ESMTP id LBpMxQamXPNcr9l4 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Fri, 23 Sep 2016 12:04:26 -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 1bnVln-0007kY-K3; Fri, 23 Sep 2016 19:04:23 +0000 Date: Fri, 23 Sep 2016 20:04:23 +0100 From: Al Viro To: Linus Torvalds Subject: [PATCH 06/11] new helper: add_to_pipe() Message-ID: <20160923190423.GD2356@ZenIV.linux.org.uk> X-ASG-Orig-Subj: [PATCH 06/11] new helper: add_to_pipe() 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: 1474657466 X-Barracuda-Encrypted: ECDHE-RSA-AES256-GCM-SHA384 X-Barracuda-URL: https://192.48.176.15:443/cgi-mod/mark.cgi X-Barracuda-Scan-Msg-Size: 5571 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 single-buffer analogue of splice_to_pipe(); vmsplice_to_pipe() switched to that, leaving splice_to_pipe() only for ->splice_read() instances (and that only until they are converted as well). Signed-off-by: Al Viro --- fs/splice.c | 109 ++++++++++++++++++++++++++++--------------------- include/linux/splice.h | 2 + 2 files changed, 64 insertions(+), 47 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 9ce6e62..085ad37 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -203,8 +203,6 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe, buf->len = spd->partial[page_nr].len; buf->private = spd->partial[page_nr].private; buf->ops = spd->ops; - if (spd->flags & SPLICE_F_GIFT) - buf->flags |= PIPE_BUF_FLAG_GIFT; pipe->nrbufs++; page_nr++; @@ -225,6 +223,27 @@ out: } EXPORT_SYMBOL_GPL(splice_to_pipe); +ssize_t add_to_pipe(struct pipe_inode_info *pipe, struct pipe_buffer *buf) +{ + int ret; + + if (unlikely(!pipe->readers)) { + send_sig(SIGPIPE, current, 0); + ret = -EPIPE; + } else if (pipe->nrbufs == pipe->buffers) { + ret = -EAGAIN; + } else { + int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); + pipe->bufs[newbuf] = *buf; + pipe->nrbufs++; + return buf->len; + } + buf->ops->release(pipe, buf); + buf->ops = NULL; + return ret; +} +EXPORT_SYMBOL(add_to_pipe); + void spd_release_page(struct splice_pipe_desc *spd, unsigned int i) { put_page(spd->pages[i]); @@ -1436,33 +1455,50 @@ static long do_splice(struct file *in, loff_t __user *off_in, return -EINVAL; } -static int get_iovec_page_array(const struct iov_iter *from, - struct page **pages, - struct partial_page *partial, - unsigned int pipe_buffers) +static int iter_to_pipe(struct iov_iter *from, + struct pipe_inode_info *pipe, + unsigned flags) { - struct iov_iter i = *from; - int buffers = 0; - while (iov_iter_count(&i)) { + struct pipe_buffer buf = { + .ops = &user_page_pipe_buf_ops, + .flags = flags + }; + size_t total = 0; + int ret = 0; + bool failed = false; + + while (iov_iter_count(from) && !failed) { + struct page *pages[16]; ssize_t copied; size_t start; + int n; - copied = iov_iter_get_pages(&i, pages + buffers, ~0UL, - pipe_buffers - buffers, &start); - if (copied <= 0) - return buffers ? buffers : copied; + copied = iov_iter_get_pages(from, pages, ~0UL, 16, &start); + if (copied <= 0) { + ret = copied; + break; + } - iov_iter_advance(&i, copied); - while (copied) { + for (n = 0; copied; n++, start = 0) { int size = min_t(int, copied, PAGE_SIZE - start); - partial[buffers].offset = start; - partial[buffers].len = size; + if (!failed) { + buf.page = pages[n]; + buf.offset = start; + buf.len = size; + ret = add_to_pipe(pipe, &buf); + if (unlikely(ret < 0)) { + failed = true; + } else { + iov_iter_advance(from, ret); + total += ret; + } + } else { + put_page(pages[n]); + } copied -= size; - start = 0; - buffers++; } } - return buffers; + return total ? total : ret; } static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, @@ -1523,19 +1559,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov, 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 = { - .pages = pages, - .partial = partial, - .nr_pages_max = PIPE_DEF_BUFFERS, - .flags = flags, - .ops = &user_page_pipe_buf_ops, - .spd_release = spd_release_page, - }; long ret, total = 0; + unsigned buf_flag = 0; int bogus_count; + if (flags & SPLICE_F_GIFT) + buf_flag = PIPE_BUF_FLAG_GIFT; + pipe = get_pipe_info(file); if (!pipe) return -EBADF; @@ -1545,27 +1575,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov, if (ret < 0) return ret; - if (splice_grow_spd(pipe, &spd)) { - kfree(iov); - return -ENOMEM; - } - pipe_lock(pipe); bogus_count = pipe->buffers; do { bogus_count += pipe->nrbufs; - 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; - break; - } - ret = splice_to_pipe(pipe, &spd); - if (ret > 0) { + ret = iter_to_pipe(&from, pipe, buf_flag); + if (ret > 0) total += ret; - iov_iter_advance(&from, ret); - } bogus_count -= pipe->nrbufs; if (bogus_count <= 0) break; @@ -1575,7 +1591,6 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov, wakeup_pipe_readers(pipe); ret = total; } - splice_shrink_spd(&spd); kfree(iov); return ret; } diff --git a/include/linux/splice.h b/include/linux/splice.h index da2751d..58b300f 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -72,6 +72,8 @@ extern ssize_t __splice_from_pipe(struct pipe_inode_info *, struct splice_desc *, splice_actor *); extern ssize_t splice_to_pipe(struct pipe_inode_info *, struct splice_pipe_desc *); +extern ssize_t add_to_pipe(struct pipe_inode_info *, + struct pipe_buffer *); extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, splice_direct_actor *);