GIT 690b4da0aa4b409b89b39b535bd03f1f3a3f92a0 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git#splice commit 690b4da0aa4b409b89b39b535bd03f1f3a3f92a0 Author: Jens Axboe Date: Fri Apr 28 13:20:00 2006 +0200 [PATCH] vmsplice: allow user to pass in gift pages If SPLICE_F_GIFT is set, the user is basically giving this pages away to the kernel. That means we can steal them for eg page cache uses instead of copying it. The data must be properly page aligned and also a multiple of the page size in length. Signed-off-by: Jens Axboe --- diff --git a/fs/splice.c b/fs/splice.c index a46ddd2..479f8be 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -166,6 +166,9 @@ static struct pipe_buf_operations page_c static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { + if (buf->flags & PIPE_BUF_FLAG_GIFT) + return 0; + return 1; } @@ -210,6 +213,9 @@ static ssize_t splice_to_pipe(struct pip 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; @@ -1095,7 +1101,7 @@ static long do_splice(struct file *in, l */ 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; @@ -1135,6 +1141,15 @@ static int get_iovec_page_array(const st * 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; @@ -1228,7 +1243,8 @@ static long do_vmsplice(struct file *fil 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; diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 0008d4b..b4afcf8 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -7,6 +7,7 @@ #define PIPE_BUF_FLAG_STOLEN 0x01 #define PIPE_BUF_FLAG_LRU 0x02 +#define PIPE_BUF_FLAG_GIFT 0x04 struct pipe_buffer { struct page *page; @@ -60,6 +61,7 @@ void __free_pipe_info(struct pipe_inode_ /* 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