aboutsummaryrefslogtreecommitdiffstats
path: root/fs/splice.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/splice.c')
-rw-r--r--fs/splice.c28
1 files changed, 25 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