[PATCH] Introduce sys_splice() system call
This adds support for the sys_splice system call. Using a pipe as a transport, it can connect to files or sockets (latter as output only). From the splice.c comments: "splice": joining two ropes together by interweaving their strands. This is the "extended pipe" functionality, where a pipe is used as an arbitrary in-memory buffer. Think of a pipe as a small kernel buffer that you can use to transfer data from one end to the other. The traditional unix read/write is extended with a "splice()" operation that transfers data buffers to or from a pipe buffer. Named by Larry McVoy, original implementation from Linus, extended by Jens to support splicing to files and fixing the initial implementation bugs. Signed-off-by: Jens Axboe <axboe@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:

committed by
Linus Torvalds

parent
5d4fe2c1ce
commit
5274f052e7
33
fs/pipe.c
33
fs/pipe.c
@@ -15,6 +15,7 @@
|
||||
#include <linux/pipe_fs_i.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/ioctls.h>
|
||||
@@ -94,11 +95,20 @@ static void anon_pipe_buf_release(struct pipe_inode_info *info, struct pipe_buff
|
||||
{
|
||||
struct page *page = buf->page;
|
||||
|
||||
if (info->tmp_page) {
|
||||
__free_page(page);
|
||||
/*
|
||||
* If nobody else uses this page, and we don't already have a
|
||||
* temporary page, let's keep track of it as a one-deep
|
||||
* allocation cache
|
||||
*/
|
||||
if (page_count(page) == 1 && !info->tmp_page) {
|
||||
info->tmp_page = page;
|
||||
return;
|
||||
}
|
||||
info->tmp_page = page;
|
||||
|
||||
/*
|
||||
* Otherwise just release our reference to it
|
||||
*/
|
||||
page_cache_release(page);
|
||||
}
|
||||
|
||||
static void *anon_pipe_buf_map(struct file *file, struct pipe_inode_info *info, struct pipe_buffer *buf)
|
||||
@@ -152,6 +162,11 @@ pipe_readv(struct file *filp, const struct iovec *_iov,
|
||||
chars = total_len;
|
||||
|
||||
addr = ops->map(filp, info, buf);
|
||||
if (IS_ERR(addr)) {
|
||||
if (!ret)
|
||||
ret = PTR_ERR(addr);
|
||||
break;
|
||||
}
|
||||
error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars);
|
||||
ops->unmap(info, buf);
|
||||
if (unlikely(error)) {
|
||||
@@ -254,8 +269,16 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
|
||||
struct pipe_buf_operations *ops = buf->ops;
|
||||
int offset = buf->offset + buf->len;
|
||||
if (ops->can_merge && offset + chars <= PAGE_SIZE) {
|
||||
void *addr = ops->map(filp, info, buf);
|
||||
int error = pipe_iov_copy_from_user(offset + addr, iov, chars);
|
||||
void *addr;
|
||||
int error;
|
||||
|
||||
addr = ops->map(filp, info, buf);
|
||||
if (IS_ERR(addr)) {
|
||||
error = PTR_ERR(addr);
|
||||
goto out;
|
||||
}
|
||||
error = pipe_iov_copy_from_user(offset + addr, iov,
|
||||
chars);
|
||||
ops->unmap(info, buf);
|
||||
ret = error;
|
||||
do_wakeup = 1;
|
||||
|
Reference in New Issue
Block a user