<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">
<br id="lineBreakAtBeginningOfMessage">
<div><br>
<blockquote type="cite">
<div>On 9 Jan 2024, at 9:40 PM, Alexey Kuznetsov <kuznet@virtuozzo.com> wrote:</div>
<br class="Apple-interchange-newline">
<div>
<div>Unfortunately, existing support of splice in fuse is completely useless,<br>
it has many flaws, each of them is fatal, even taken separately.<br>
<br>
- it passes only single splice, which requires of user space<br>
to prepare one more splice to merge header.<br>
- ... and does not allow to use splices coming from TCP as they<br>
can be huge and do not fit to single pipe buffer.<br>
- it uses kvmalloc(!!!) for temp buffer, which is very expensive<br>
<br>
Nevertheless, using splices to transfer date from network is the only<br>
our chance to get some reasonable throughput. F.e. without splice<br>
we cannot saturate even single 100G ethernet.<br>
<br>
So, the following approach suggested, which is the simplest and<br>
the cleanest for FUSE_READ. Extend existing fuse reply<br>
messages, allowing it to carry metadata instead of data. Metadata<br>
is a list of pipe file descriptors, which can be processed one by one,<br>
sucking pages from them.<br>
<br>
Extensions are possible, though as it is now, only FUSE_READ<br>
needs this. One day we probably will want to use it with FUSE_IOCTL,<br>
other request types do not carry any significant data.<br>
<br>
With this patch we are finally able to saturate 100G ethernet,<br>
higher speeds are still not tested.<br>
<br>
Signed-off-by: Alexey Kuznetsov <kuznet@acronis.com><br>
---<br>
fs/fuse/dev.c | 155 +++++++++++++++++++++++++++++++++++++++++++++-<br>
include/uapi/linux/fuse.h | 3 +<br>
2 files changed, 156 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c<br>
index 59b9465..ccc30d9 100644<br>
--- a/fs/fuse/dev.c<br>
+++ b/fs/fuse/dev.c<br>
@@ -31,6 +31,7 @@<br>
<br>
static struct kmem_cache *fuse_req_cachep;<br>
extern struct workqueue_struct *fuse_fput_wq;<br>
+static const struct file_operations *fuse_g_splice_ops;<br>
<br>
static struct fuse_dev *fuse_get_dev(struct file *file)<br>
{<br>
@@ -1997,6 +1998,144 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args,<br>
<span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span> args->out_args, args->page_zeroing);<br>
}<br>
<br>
+static int copy_out_splices(struct fuse_copy_state *cs, struct fuse_args *args,<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span> unsigned int nbytes)<br>
+{<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>struct fuse_args_pages *ap = container_of(args, typeof(*ap), args);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>struct pipe_inode_info *pipe;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>u32 fdarr_inline[8];<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>u32 *fdarr;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>unsigned int nsplices;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>int err, i;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>int didx = 0;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>int doff = ap->descs[0].offset;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>int dend = doff + ap->descs[0].length;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>struct page *dpage = ap->pages[0];<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>nsplices = nbytes - sizeof(struct fuse_out_header);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>if (nsplices & 3)<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>return -EINVAL;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>if (nsplices > 8) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>fdarr = kmalloc(nsplices, GFP_KERNEL);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>if (!fdarr)<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>return -ENOMEM;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>} else<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>fdarr = fdarr_inline;<br>
<font color="#000000"></font></div>
</div>
</blockquote>
</div>
<blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;">
<div>
<div>
<div><font color="#000000"><br>
</font></div>
</div>
</div>
</blockquote>
Is this a mistake that the condition for kmalloc should be "nsplices > 8 * 4” ? <br>
<div><br>
<blockquote type="cite">
<div>
<div>+<span class="Apple-tab-span" style="white-space:pre"> </span>err = fuse_copy_one(cs, fdarr, nsplices);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>if (err)<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>goto out;<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>nsplices /= 4;<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>fuse_copy_finish(cs);<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>for (i = 0; i < nsplices; i++) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>void *src, *dst;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>struct fd f = fdget(fdarr[i]);<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>if (f.file) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>unsigned int head, tail, mask;<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>if (unlikely(f.file->f_op != fuse_g_splice_ops)) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>if (fuse_g_splice_ops
== NULL) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>struct
file *probe_files[2];<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>if
(create_pipe_files(probe_files, 0)) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>err
= -EBADF;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>goto
out;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>fuse_g_splice_ops
= probe_files[0]->f_op;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>fput(probe_files[0]);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>fput(probe_files[1]);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>if (unlikely(f.file->f_op
!= fuse_g_splice_ops)) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>err
= -EBADF;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>goto
out;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>pipe = f.file->private_data;<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>if (pipe == NULL) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>err = -EBADF;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>goto out;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>pipe_lock(pipe);<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>head = pipe->head;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>mask = pipe->ring_size - 1;<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>for (tail = pipe->tail; tail != head; tail++) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>struct page *ipage
= pipe->bufs[tail & mask].page;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>int ioff = pipe->bufs[tail
& mask].offset;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>int ilen = pipe->bufs[tail
& mask].len;<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>while (ilen > 0)
{<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>int
copy = ilen;<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>if
(doff >= dend) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>didx++;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>if
(didx >= ap->num_pages)<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>goto
out_overflow;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>dpage
= ap->pages[didx];<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>doff
= ap->descs[didx].offset;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>dend
= doff + ap->descs[didx].length;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>if
(copy > dend - doff)<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>copy
= dend - doff;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>src
= kmap_atomic(ipage);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>dst
= kmap_atomic(dpage);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>memcpy(dst
+ doff, src + ioff, copy);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>kunmap_atomic(dst);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>kunmap_atomic(src);<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>doff
+= copy;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>ioff
+= copy;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>ilen
-= copy;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>put_page(ipage);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>pipe->bufs[tail
& mask].ops = NULL;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>pipe->bufs[tail
& mask].page = NULL;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>pipe->tail = tail
+ 1;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>pipe_unlock(pipe);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>fdput(f);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>} else {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>err = -EBADF;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>goto out;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>}<br>
<br>
</div>
</div>
</blockquote>
Is it difficult to separate the verification of inputs, such as fds, size of src buffs against dest buffs etc, from the process of copying data? Similar to what’s been done in ‘copy_out_args()’. <br>
<br>
<blockquote type="cite">
<div>
<div>+<span class="Apple-tab-span" style="white-space:pre"> </span>if (args->page_zeroing && didx < ap->num_pages) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>if (doff < dend) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>void *dst = kmap_atomic(dpage);<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>memset(dst + doff, 0, dend - doff);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>kunmap_atomic(dst);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>for (didx++ ; didx < ap->num_pages; didx++) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>void *dst = kmap_atomic(ap->pages[didx]);<br>
+<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>memset(dst + ap->descs[didx].offset, 0, ap->descs[didx].length);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>kunmap_atomic(dst);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>err = 0;<br>
+<br>
+out:<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>if (fdarr != fdarr_inline)<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>kfree(fdarr);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>return err;<br>
+<br>
+out_overflow:<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>pipe_unlock(pipe);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>err = -EMSGSIZE;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>goto out;<br>
+}<br>
+<br>
/*<br>
* Write a single reply to a request. First the header is copied from<br>
* the write buffer. The request is then searched on the processing<br>
@@ -2035,7 +2174,8 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,<br>
<span class="Apple-tab-span" style="white-space:pre"></span>}<br>
<br>
<span class="Apple-tab-span" style="white-space:pre"></span>err = -EINVAL;<br>
-<span class="Apple-tab-span" style="white-space:pre"> </span>if (oh.error <= -512 || oh.error > 0)<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>if (oh.error != FUSE_OUT_SPLICES &&<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span> (oh.error <= -512 || oh.error > 0))<br>
<span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>goto copy_finish;<br>
<br>
<span class="Apple-tab-span" style="white-space:pre"></span>spin_lock(&fpq->lock);<br>
@@ -2067,6 +2207,14 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,<br>
<span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>goto copy_finish;<br>
<span class="Apple-tab-span" style="white-space:pre"></span>}<br>
<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>if (oh.error == FUSE_OUT_SPLICES) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>if (req->args->out_numargs != 1 || !req->args->out_pages) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>spin_unlock(&fpq->lock);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>err = -EINVAL;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>goto copy_finish;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>}<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>}<br>
+<br>
<span class="Apple-tab-span" style="white-space:pre"></span>clear_bit(FR_SENT, &req->flags);<br>
<span class="Apple-tab-span" style="white-space:pre"></span>list_move(&req->list, &fpq->io);<br>
<span class="Apple-tab-span" style="white-space:pre"></span>req->out.h = oh;<br>
@@ -2076,7 +2224,10 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,<br>
<span class="Apple-tab-span" style="white-space:pre"></span>if (!req->args->page_replace)<br>
<span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>cs->move_pages = 0;<br>
<br>
-<span class="Apple-tab-span" style="white-space:pre"> </span>if (oh.error)<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>if (oh.error == FUSE_OUT_SPLICES) {<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>req->out.h.error = 0;<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre"></span>err = copy_out_splices(cs, req->args, nbytes);<br>
+<span class="Apple-tab-span" style="white-space:pre"> </span>} else if (oh.error)<br>
<span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>err = nbytes != sizeof(oh) ? -EINVAL : 0;<br>
<span class="Apple-tab-span" style="white-space:pre"></span>else<br>
<span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span>err = copy_out_args(cs, req->args, nbytes);<br>
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h<br>
index 607b1c1..0529595 100644<br>
--- a/include/uapi/linux/fuse.h<br>
+++ b/include/uapi/linux/fuse.h<br>
@@ -875,6 +875,9 @@ struct fuse_out_header {<br>
<span class="Apple-tab-span" style="white-space:pre"></span>uint64_t<span class="Apple-tab-span" style="white-space:pre">
</span>unique;<br>
};<br>
<br>
+/* Special error value for fuse_out_header */<br>
+#define FUSE_OUT_SPLICES<span class="Apple-tab-span" style="white-space:pre"> </span>
0x40000000<br>
+<br>
struct fuse_dirent {<br>
<span class="Apple-tab-span" style="white-space:pre"></span>uint64_t<span class="Apple-tab-span" style="white-space:pre">
</span>ino;<br>
<span class="Apple-tab-span" style="white-space:pre"></span>uint64_t<span class="Apple-tab-span" style="white-space:pre">
</span>off;<br>
-- <br>
1.8.3.1<br>
<br>
</div>
</div>
</blockquote>
</div>
<br>
</body>
</html>