[PATCH v2] fs/splice: ignore flag SPLICE_F_GIFT in syscall vmsplice
From: Konstantin Khlebnikov
Date: Thu Nov 14 2019 - 09:13:19 EST
Generic support of flag SPLICE_F_MOVE in syscall splice was removed in
kernel 2.6.21 commit 485ddb4b9741 ("1/2 splice: dont steal").
Infrastructure stay intact and this feature may came back.
At least driver or filesystem could provide own implementation.
But stealing mapped pages from userspace never worked and is very
unlikely that will ever make sense due to unmapping overhead.
Also lru handling is broken if gifted anon page spliced into file.
Let's seal entry point for marking page as a gift in vmsplice.
v2: remove PIPE_BUF_FLAG_GIFT and related dead code.
Signed-off-by: Konstantin Khlebnikov <khlebnikov@xxxxxxxxxxxxxx>
Link: https://lore.kernel.org/lkml/CAHk-=wgPQutQ8d8kUCvAFi+hfNWgaNLiZPkbg-GXY2DCtD-Z5Q@xxxxxxxxxxxxxx/
---
fs/fuse/dev.c | 1 -
fs/splice.c | 41 +++--------------------------------------
include/linux/pipe_fs_i.h | 1 -
3 files changed, 3 insertions(+), 40 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index ed1abc9e33cf..aacc4fa639ba 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1987,7 +1987,6 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
goto out_free;
*obuf = *ibuf;
- obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
obuf->len = rem;
ibuf->offset += obuf->len;
ibuf->len -= obuf->len;
diff --git a/fs/splice.c b/fs/splice.c
index 98412721f056..6cc5098b164b 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -145,23 +145,6 @@ const struct pipe_buf_operations page_cache_pipe_buf_ops = {
.get = generic_pipe_buf_get,
};
-static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
- struct pipe_buffer *buf)
-{
- if (!(buf->flags & PIPE_BUF_FLAG_GIFT))
- return 1;
-
- buf->flags |= PIPE_BUF_FLAG_LRU;
- return generic_pipe_buf_steal(pipe, buf);
-}
-
-static const struct pipe_buf_operations user_page_pipe_buf_ops = {
- .confirm = generic_pipe_buf_confirm,
- .release = page_cache_pipe_buf_release,
- .steal = user_page_pipe_buf_steal,
- .get = generic_pipe_buf_get,
-};
-
static void wakeup_pipe_readers(struct pipe_inode_info *pipe)
{
smp_mb();
@@ -1197,12 +1180,10 @@ static long do_splice(struct file *in, loff_t __user *off_in,
}
static int iter_to_pipe(struct iov_iter *from,
- struct pipe_inode_info *pipe,
- unsigned flags)
+ struct pipe_inode_info *pipe)
{
struct pipe_buffer buf = {
- .ops = &user_page_pipe_buf_ops,
- .flags = flags
+ .ops = &nosteal_pipe_buf_ops,
};
size_t total = 0;
int ret = 0;
@@ -1286,10 +1267,6 @@ static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
{
struct pipe_inode_info *pipe;
long ret = 0;
- unsigned buf_flag = 0;
-
- if (flags & SPLICE_F_GIFT)
- buf_flag = PIPE_BUF_FLAG_GIFT;
pipe = get_pipe_info(file);
if (!pipe)
@@ -1298,7 +1275,7 @@ static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
pipe_lock(pipe);
ret = wait_for_space(pipe, flags);
if (!ret)
- ret = iter_to_pipe(iter, pipe, buf_flag);
+ ret = iter_to_pipe(iter, pipe);
pipe_unlock(pipe);
if (ret > 0)
wakeup_pipe_readers(pipe);
@@ -1601,12 +1578,6 @@ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
}
*obuf = *ibuf;
- /*
- * Don't inherit the gift flag, we need to
- * prevent multiple steals of this page.
- */
- obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
-
pipe_buf_mark_unmergeable(obuf);
obuf->len = len;
@@ -1681,12 +1652,6 @@ static int link_pipe(struct pipe_inode_info *ipipe,
obuf = opipe->bufs + nbuf;
*obuf = *ibuf;
- /*
- * Don't inherit the gift flag, we need to
- * prevent multiple steals of this page.
- */
- obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
-
pipe_buf_mark_unmergeable(obuf);
if (obuf->len > len)
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index 5c626fdc10db..1a3a5efb9c6f 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -6,7 +6,6 @@
#define PIPE_BUF_FLAG_LRU 0x01 /* page is on the LRU */
#define PIPE_BUF_FLAG_ATOMIC 0x02 /* was atomically mapped */
-#define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */
#define PIPE_BUF_FLAG_PACKET 0x08 /* read() as a packet */
/**