Skip to content

Commit

Permalink
[PATCH] Introduce sys_splice() system call
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Jens Axboe authored and Linus Torvalds committed Mar 30, 2006
1 parent 5d4fe2c commit 5274f05
Show file tree
Hide file tree
Showing 15 changed files with 669 additions and 11 deletions.
1 change: 1 addition & 0 deletions arch/i386/kernel/syscall_table.S
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,4 @@ ENTRY(sys_call_table)
.long sys_unshare /* 310 */
.long sys_set_robust_list
.long sys_get_robust_list
.long sys_splice
1 change: 1 addition & 0 deletions arch/ia64/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -1605,5 +1605,6 @@ sys_call_table:
data8 sys_ni_syscall // reserved for pselect
data8 sys_ni_syscall // 1295 reserved for ppoll
data8 sys_unshare
data8 sys_splice

.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
2 changes: 1 addition & 1 deletion fs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \
ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
ioprio.o pnode.o drop_caches.o
ioprio.o pnode.o drop_caches.o splice.o

obj-$(CONFIG_INOTIFY) += inotify.o
obj-$(CONFIG_EPOLL) += eventpoll.o
Expand Down
2 changes: 2 additions & 0 deletions fs/ext2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const struct file_operations ext2_file_operations = {
.readv = generic_file_readv,
.writev = generic_file_writev,
.sendfile = generic_file_sendfile,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
};

#ifdef CONFIG_EXT2_FS_XIP
Expand Down
2 changes: 2 additions & 0 deletions fs/ext3/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ const struct file_operations ext3_file_operations = {
.release = ext3_release_file,
.fsync = ext3_sync_file,
.sendfile = generic_file_sendfile,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
};

struct inode_operations ext3_file_inode_operations = {
Expand Down
33 changes: 28 additions & 5 deletions fs/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions fs/reiserfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1576,6 +1576,8 @@ const struct file_operations reiserfs_file_operations = {
.sendfile = generic_file_sendfile,
.aio_read = generic_file_aio_read,
.aio_write = reiserfs_aio_write,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
};

struct inode_operations reiserfs_file_inode_operations = {
Expand Down
Loading

0 comments on commit 5274f05

Please sign in to comment.