aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/splice.c28
-rw-r--r--include/linux/pipe_fs_i.h2
2 files changed, 27 insertions, 3 deletions
diff --git a/fs/splice.c b/fs/splice.c
index d4664a297bab..b150493b6fc3 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -141,7 +141,10 @@ static struct pipe_buf_operations page_cache_pipe_buf_ops = {
141static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, 141static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
142 struct pipe_buffer *buf) 142 struct pipe_buffer *buf)
143{ 143{
144 return 1; 144 if (!(buf->flags & PIPE_BUF_FLAG_GIFT))
145 return 1;
146
147 return 0;
145} 148}
146 149
147static struct pipe_buf_operations user_page_pipe_buf_ops = { 150static struct pipe_buf_operations user_page_pipe_buf_ops = {
@@ -186,6 +189,9 @@ static ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
186 buf->offset = spd->partial[page_nr].offset; 189 buf->offset = spd->partial[page_nr].offset;
187 buf->len = spd->partial[page_nr].len; 190 buf->len = spd->partial[page_nr].len;
188 buf->ops = spd->ops; 191 buf->ops = spd->ops;
192 if (spd->flags & SPLICE_F_GIFT)
193 buf->flags |= PIPE_BUF_FLAG_GIFT;
194
189 pipe->nrbufs++; 195 pipe->nrbufs++;
190 page_nr++; 196 page_nr++;
191 ret += buf->len; 197 ret += buf->len;
@@ -1073,7 +1079,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
1073 */ 1079 */
1074static int get_iovec_page_array(const struct iovec __user *iov, 1080static int get_iovec_page_array(const struct iovec __user *iov,
1075 unsigned int nr_vecs, struct page **pages, 1081 unsigned int nr_vecs, struct page **pages,
1076 struct partial_page *partial) 1082 struct partial_page *partial, int aligned)
1077{ 1083{
1078 int buffers = 0, error = 0; 1084 int buffers = 0, error = 0;
1079 1085
@@ -1113,6 +1119,15 @@ static int get_iovec_page_array(const struct iovec __user *iov,
1113 * in the user pages. 1119 * in the user pages.
1114 */ 1120 */
1115 off = (unsigned long) base & ~PAGE_MASK; 1121 off = (unsigned long) base & ~PAGE_MASK;
1122
1123 /*
1124 * If asked for alignment, the offset must be zero and the
1125 * length a multiple of the PAGE_SIZE.
1126 */
1127 error = -EINVAL;
1128 if (aligned && (off || len & ~PAGE_MASK))
1129 break;
1130
1116 npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT; 1131 npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
1117 if (npages > PIPE_BUFFERS - buffers) 1132 if (npages > PIPE_BUFFERS - buffers)
1118 npages = PIPE_BUFFERS - buffers; 1133 npages = PIPE_BUFFERS - buffers;
@@ -1206,7 +1221,8 @@ static long do_vmsplice(struct file *file, const struct iovec __user *iov,
1206 else if (unlikely(!nr_segs)) 1221 else if (unlikely(!nr_segs))
1207 return 0; 1222 return 0;
1208 1223
1209 spd.nr_pages = get_iovec_page_array(iov, nr_segs, pages, partial); 1224 spd.nr_pages = get_iovec_page_array(iov, nr_segs, pages, partial,
1225 flags & SPLICE_F_GIFT);
1210 if (spd.nr_pages <= 0) 1226 if (spd.nr_pages <= 0)
1211 return spd.nr_pages; 1227 return spd.nr_pages;
1212 1228
@@ -1314,6 +1330,12 @@ static int link_pipe(struct pipe_inode_info *ipipe,
1314 obuf = opipe->bufs + nbuf; 1330 obuf = opipe->bufs + nbuf;
1315 *obuf = *ibuf; 1331 *obuf = *ibuf;
1316 1332
1333 /*
1334 * Don't inherit the gift flag, we need to
1335 * prevent multiple steals of this page.
1336 */
1337 obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
1338
1317 if (obuf->len > len) 1339 if (obuf->len > len)
1318 obuf->len = len; 1340 obuf->len = len;
1319 1341
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index 4c054491e38e..df4d3fa7d3dc 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -7,6 +7,7 @@
7 7
8#define PIPE_BUF_FLAG_LRU 0x01 /* page is on the LRU */ 8#define PIPE_BUF_FLAG_LRU 0x01 /* page is on the LRU */
9#define PIPE_BUF_FLAG_ATOMIC 0x02 /* was atomically mapped */ 9#define PIPE_BUF_FLAG_ATOMIC 0x02 /* was atomically mapped */
10#define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */
10 11
11struct pipe_buffer { 12struct pipe_buffer {
12 struct page *page; 13 struct page *page;
@@ -79,6 +80,7 @@ int generic_pipe_buf_pin(struct pipe_inode_info *, struct pipe_buffer *);
79 /* we may still block on the fd we splice */ 80 /* we may still block on the fd we splice */
80 /* from/to, of course */ 81 /* from/to, of course */
81#define SPLICE_F_MORE (0x04) /* expect more data */ 82#define SPLICE_F_MORE (0x04) /* expect more data */
83#define SPLICE_F_GIFT (0x08) /* pages passed in are a gift */
82 84
83/* 85/*
84 * Passed to the actors 86 * Passed to the actors