static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
- return 1;
+ if (!(buf->flags & PIPE_BUF_FLAG_GIFT))
+ return 1;
+
+ return 0;
}
static struct pipe_buf_operations user_page_pipe_buf_ops = {
buf->offset = spd->partial[page_nr].offset;
buf->len = spd->partial[page_nr].len;
buf->ops = spd->ops;
+ if (spd->flags & SPLICE_F_GIFT)
+ buf->flags |= PIPE_BUF_FLAG_GIFT;
+
pipe->nrbufs++;
page_nr++;
ret += buf->len;
*/
page = find_get_page(mapping, index);
if (!page) {
+ /*
+ * Make sure the read-ahead engine is notified
+ * about this failure.
+ */
+ handle_ra_miss(mapping, &in->f_ra, index);
+
/*
* page didn't exist, allocate one.
*/
/*
* Careful, ->map() uses KM_USER0!
*/
- char *src = buf->ops->map(info, buf);
+ char *src = buf->ops->map(info, buf, 1);
char *dst = kmap_atomic(page, KM_USER1);
memcpy(dst + offset, src + buf->offset, this_len);
flush_dcache_page(page);
kunmap_atomic(dst, KM_USER1);
- buf->ops->unmap(info, buf);
+ buf->ops->unmap(info, buf, src);
}
ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len);
*/
static int get_iovec_page_array(const struct iovec __user *iov,
unsigned int nr_vecs, struct page **pages,
- struct partial_page *partial)
+ struct partial_page *partial, int aligned)
{
int buffers = 0, error = 0;
* in the user pages.
*/
off = (unsigned long) base & ~PAGE_MASK;
+
+ /*
+ * If asked for alignment, the offset must be zero and the
+ * length a multiple of the PAGE_SIZE.
+ */
+ error = -EINVAL;
+ if (aligned && (off || len & ~PAGE_MASK))
+ break;
+
npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (npages > PIPE_BUFFERS - buffers)
npages = PIPE_BUFFERS - buffers;
else if (unlikely(!nr_segs))
return 0;
- spd.nr_pages = get_iovec_page_array(iov, nr_segs, pages, partial);
+ spd.nr_pages = get_iovec_page_array(iov, nr_segs, pages, partial,
+ flags & SPLICE_F_GIFT);
if (spd.nr_pages <= 0)
return spd.nr_pages;
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;
+
if (obuf->len > len)
obuf->len = len;