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;
*/
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;
#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 */
struct pipe_buffer {
struct page *page;
/* we may still block on the fd we splice */
/* from/to, of course */
#define SPLICE_F_MORE (0x04) /* expect more data */
+#define SPLICE_F_GIFT (0x08) /* pages passed in are a gift */
/*
* Passed to the actors