summaryrefslogtreecommitdiff
path: root/fs/splice.c
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2022-06-29 16:06:58 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-08-21 16:15:47 +0300
commit36ba38996001ffc0690c79f74a6daad0ea4dae7e (patch)
treec3d259db8600d72ea824507316d57c37e3e1259c /fs/splice.c
parent7430e587643af437058ce0b92545dedf0a07957b (diff)
downloadlinux-36ba38996001ffc0690c79f74a6daad0ea4dae7e.tar.xz
fs: check FMODE_LSEEK to control internal pipe splicing
[ Upstream commit 97ef77c52b789ec1411d360ed99dca1efe4b2c81 ] The original direct splicing mechanism from Jens required the input to be a regular file because it was avoiding the special socket case. It also recognized blkdevs as being close enough to a regular file. But it forgot about chardevs, which behave the same way and work fine here. This is an okayish heuristic, but it doesn't totally work. For example, a few chardevs should be spliceable here. And a few regular files shouldn't. This patch fixes this by instead checking whether FMODE_LSEEK is set, which represents decently enough what we need rewinding for when splicing to internal pipes. Fixes: b92ce5589374 ("[PATCH] splice: add direct fd <-> fd splicing support") Cc: Jens Axboe <axboe@kernel.dk> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'fs/splice.c')
-rw-r--r--fs/splice.c10
1 files changed, 4 insertions, 6 deletions
diff --git a/fs/splice.c b/fs/splice.c
index 866d5c2367b2..6610e55c0e2a 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -806,17 +806,15 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
{
struct pipe_inode_info *pipe;
long ret, bytes;
- umode_t i_mode;
size_t len;
int i, flags, more;
/*
- * We require the input being a regular file, as we don't want to
- * randomly drop data for eg socket -> socket splicing. Use the
- * piped splicing for that!
+ * We require the input to be seekable, as we don't want to randomly
+ * drop data for eg socket -> socket splicing. Use the piped splicing
+ * for that!
*/
- i_mode = file_inode(in)->i_mode;
- if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode)))
+ if (unlikely(!(in->f_mode & FMODE_LSEEK)))
return -EINVAL;
/*