diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-26 10:47:55 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-26 10:47:55 -0400 |
| commit | 7b97ebfb931887be63bfa29b6c143e9e9da3f5e8 (patch) | |
| tree | faaf77f68ef4192ac1a3c23f43fed122a080d341 | |
| parent | 07db8696f5d484485dde77138ff87d19c8628a75 (diff) | |
| parent | 1ebd32fc54bd04de6b3944587f25513c0681f98e (diff) | |
Merge branch 'splice' of git://brick.kernel.dk/data/git/linux-2.6-block
* 'splice' of git://brick.kernel.dk/data/git/linux-2.6-block:
[PATCH] splice: add ->splice_write support for /dev/null
[PATCH] splice: rearrange moving to/from pipe helpers
[PATCH] Add support for the sys_vmsplice syscall
[PATCH] splice: fix offset problems
[PATCH] splice: fix min() warning
| -rw-r--r-- | arch/ia64/kernel/entry.S | 1 | ||||
| -rw-r--r-- | arch/powerpc/kernel/systbl.S | 1 | ||||
| -rw-r--r-- | arch/powerpc/platforms/cell/spu_callbacks.c | 1 | ||||
| -rw-r--r-- | drivers/char/mem.c | 14 | ||||
| -rw-r--r-- | fs/splice.c | 355 | ||||
| -rw-r--r-- | include/asm-i386/unistd.h | 3 | ||||
| -rw-r--r-- | include/asm-ia64/unistd.h | 3 | ||||
| -rw-r--r-- | include/asm-powerpc/unistd.h | 3 | ||||
| -rw-r--r-- | include/asm-x86_64/unistd.h | 4 | ||||
| -rw-r--r-- | include/linux/pipe_fs_i.h | 17 | ||||
| -rw-r--r-- | include/linux/syscalls.h | 3 |
11 files changed, 328 insertions, 77 deletions
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index e307988112..bcb80ca5cf 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S | |||
| @@ -1610,5 +1610,6 @@ sys_call_table: | |||
| 1610 | data8 sys_get_robust_list | 1610 | data8 sys_get_robust_list |
| 1611 | data8 sys_sync_file_range // 1300 | 1611 | data8 sys_sync_file_range // 1300 |
| 1612 | data8 sys_tee | 1612 | data8 sys_tee |
| 1613 | data8 sys_vmsplice | ||
| 1613 | 1614 | ||
| 1614 | .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls | 1615 | .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls |
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 8d15226905..0b98eea73c 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S | |||
| @@ -324,6 +324,7 @@ COMPAT_SYS(ppoll) | |||
| 324 | SYSCALL(unshare) | 324 | SYSCALL(unshare) |
| 325 | SYSCALL(splice) | 325 | SYSCALL(splice) |
| 326 | SYSCALL(tee) | 326 | SYSCALL(tee) |
| 327 | SYSCALL(vmsplice) | ||
| 327 | 328 | ||
| 328 | /* | 329 | /* |
| 329 | * please add new calls to arch/powerpc/platforms/cell/spu_callbacks.c | 330 | * please add new calls to arch/powerpc/platforms/cell/spu_callbacks.c |
diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c index deb3afb944..b283380a2a 100644 --- a/arch/powerpc/platforms/cell/spu_callbacks.c +++ b/arch/powerpc/platforms/cell/spu_callbacks.c | |||
| @@ -318,6 +318,7 @@ void *spu_syscall_table[] = { | |||
| 318 | [__NR_unshare] sys_unshare, | 318 | [__NR_unshare] sys_unshare, |
| 319 | [__NR_splice] sys_splice, | 319 | [__NR_splice] sys_splice, |
| 320 | [__NR_tee] sys_tee, | 320 | [__NR_tee] sys_tee, |
| 321 | [__NR_vmsplice] sys_vmsplice, | ||
| 321 | }; | 322 | }; |
| 322 | 323 | ||
| 323 | long spu_sys_callback(struct spu_syscall_block *s) | 324 | long spu_sys_callback(struct spu_syscall_block *s) |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 66719f9d29..1fa9fa157c 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/crash_dump.h> | 27 | #include <linux/crash_dump.h> |
| 28 | #include <linux/backing-dev.h> | 28 | #include <linux/backing-dev.h> |
| 29 | #include <linux/bootmem.h> | 29 | #include <linux/bootmem.h> |
| 30 | #include <linux/pipe_fs_i.h> | ||
| 30 | 31 | ||
| 31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 32 | #include <asm/io.h> | 33 | #include <asm/io.h> |
| @@ -578,6 +579,18 @@ static ssize_t write_null(struct file * file, const char __user * buf, | |||
| 578 | return count; | 579 | return count; |
| 579 | } | 580 | } |
| 580 | 581 | ||
| 582 | static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf, | ||
| 583 | struct splice_desc *sd) | ||
| 584 | { | ||
| 585 | return sd->len; | ||
| 586 | } | ||
| 587 | |||
| 588 | static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out, | ||
| 589 | loff_t *ppos, size_t len, unsigned int flags) | ||
| 590 | { | ||
| 591 | return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); | ||
| 592 | } | ||
| 593 | |||
| 581 | #ifdef CONFIG_MMU | 594 | #ifdef CONFIG_MMU |
| 582 | /* | 595 | /* |
| 583 | * For fun, we are using the MMU for this. | 596 | * For fun, we are using the MMU for this. |
| @@ -785,6 +798,7 @@ static struct file_operations null_fops = { | |||
| 785 | .llseek = null_lseek, | 798 | .llseek = null_lseek, |
| 786 | .read = read_null, | 799 | .read = read_null, |
| 787 | .write = write_null, | 800 | .write = write_null, |
| 801 | .splice_write = splice_write_null, | ||
| 788 | }; | 802 | }; |
| 789 | 803 | ||
| 790 | #if defined(CONFIG_ISA) || !defined(__mc68000__) | 804 | #if defined(CONFIG_ISA) || !defined(__mc68000__) |
diff --git a/fs/splice.c b/fs/splice.c index 0559e7577a..447ebc0a37 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -27,15 +27,22 @@ | |||
| 27 | #include <linux/buffer_head.h> | 27 | #include <linux/buffer_head.h> |
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/syscalls.h> | 29 | #include <linux/syscalls.h> |
| 30 | #include <linux/uio.h> | ||
| 31 | |||
| 32 | struct partial_page { | ||
| 33 | unsigned int offset; | ||
| 34 | unsigned int len; | ||
| 35 | }; | ||
| 30 | 36 | ||
| 31 | /* | 37 | /* |
| 32 | * Passed to the actors | 38 | * Passed to splice_to_pipe |
| 33 | */ | 39 | */ |
| 34 | struct splice_desc { | 40 | struct splice_pipe_desc { |
| 35 | unsigned int len, total_len; /* current and remaining length */ | 41 | struct page **pages; /* page map */ |
| 42 | struct partial_page *partial; /* pages[] may not be contig */ | ||
| 43 | int nr_pages; /* number of pages in map */ | ||
| 36 | unsigned int flags; /* splice flags */ | 44 | unsigned int flags; /* splice flags */ |
| 37 | struct file *file; /* file to read/write */ | 45 | struct pipe_buf_operations *ops;/* ops associated with output pipe */ |
| 38 | loff_t pos; /* file position */ | ||
| 39 | }; | 46 | }; |
| 40 | 47 | ||
| 41 | /* | 48 | /* |
| @@ -128,6 +135,19 @@ static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, | |||
| 128 | kunmap(buf->page); | 135 | kunmap(buf->page); |
| 129 | } | 136 | } |
| 130 | 137 | ||
| 138 | static void *user_page_pipe_buf_map(struct file *file, | ||
| 139 | struct pipe_inode_info *pipe, | ||
| 140 | struct pipe_buffer *buf) | ||
| 141 | { | ||
| 142 | return kmap(buf->page); | ||
| 143 | } | ||
| 144 | |||
| 145 | static void user_page_pipe_buf_unmap(struct pipe_inode_info *pipe, | ||
| 146 | struct pipe_buffer *buf) | ||
| 147 | { | ||
| 148 | kunmap(buf->page); | ||
| 149 | } | ||
| 150 | |||
| 131 | static void page_cache_pipe_buf_get(struct pipe_inode_info *info, | 151 | static void page_cache_pipe_buf_get(struct pipe_inode_info *info, |
| 132 | struct pipe_buffer *buf) | 152 | struct pipe_buffer *buf) |
| 133 | { | 153 | { |
| @@ -143,19 +163,33 @@ static struct pipe_buf_operations page_cache_pipe_buf_ops = { | |||
| 143 | .get = page_cache_pipe_buf_get, | 163 | .get = page_cache_pipe_buf_get, |
| 144 | }; | 164 | }; |
| 145 | 165 | ||
| 166 | static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, | ||
| 167 | struct pipe_buffer *buf) | ||
| 168 | { | ||
| 169 | return 1; | ||
| 170 | } | ||
| 171 | |||
| 172 | static struct pipe_buf_operations user_page_pipe_buf_ops = { | ||
| 173 | .can_merge = 0, | ||
| 174 | .map = user_page_pipe_buf_map, | ||
| 175 | .unmap = user_page_pipe_buf_unmap, | ||
| 176 | .release = page_cache_pipe_buf_release, | ||
| 177 | .steal = user_page_pipe_buf_steal, | ||
| 178 | .get = page_cache_pipe_buf_get, | ||
| 179 | }; | ||
| 180 | |||
| 146 | /* | 181 | /* |
| 147 | * Pipe output worker. This sets up our pipe format with the page cache | 182 | * Pipe output worker. This sets up our pipe format with the page cache |
| 148 | * pipe buffer operations. Otherwise very similar to the regular pipe_writev(). | 183 | * pipe buffer operations. Otherwise very similar to the regular pipe_writev(). |
| 149 | */ | 184 | */ |
| 150 | static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages, | 185 | static ssize_t splice_to_pipe(struct pipe_inode_info *pipe, |
| 151 | int nr_pages, unsigned long len, | 186 | struct splice_pipe_desc *spd) |
| 152 | unsigned int offset, unsigned int flags) | ||
| 153 | { | 187 | { |
| 154 | int ret, do_wakeup, i; | 188 | int ret, do_wakeup, page_nr; |
| 155 | 189 | ||
| 156 | ret = 0; | 190 | ret = 0; |
| 157 | do_wakeup = 0; | 191 | do_wakeup = 0; |
| 158 | i = 0; | 192 | page_nr = 0; |
| 159 | 193 | ||
| 160 | if (pipe->inode) | 194 | if (pipe->inode) |
| 161 | mutex_lock(&pipe->inode->i_mutex); | 195 | mutex_lock(&pipe->inode->i_mutex); |
| @@ -171,27 +205,19 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages, | |||
| 171 | if (pipe->nrbufs < PIPE_BUFFERS) { | 205 | if (pipe->nrbufs < PIPE_BUFFERS) { |
| 172 | int newbuf = (pipe->curbuf + pipe->nrbufs) & (PIPE_BUFFERS - 1); | 206 | int newbuf = (pipe->curbuf + pipe->nrbufs) & (PIPE_BUFFERS - 1); |
| 173 | struct pipe_buffer *buf = pipe->bufs + newbuf; | 207 | struct pipe_buffer *buf = pipe->bufs + newbuf; |
| 174 | struct page *page = pages[i++]; | ||
| 175 | unsigned long this_len; | ||
| 176 | 208 | ||
| 177 | this_len = PAGE_CACHE_SIZE - offset; | 209 | buf->page = spd->pages[page_nr]; |
| 178 | if (this_len > len) | 210 | buf->offset = spd->partial[page_nr].offset; |
| 179 | this_len = len; | 211 | buf->len = spd->partial[page_nr].len; |
| 180 | 212 | buf->ops = spd->ops; | |
| 181 | buf->page = page; | ||
| 182 | buf->offset = offset; | ||
| 183 | buf->len = this_len; | ||
| 184 | buf->ops = &page_cache_pipe_buf_ops; | ||
| 185 | pipe->nrbufs++; | 213 | pipe->nrbufs++; |
| 214 | page_nr++; | ||
| 215 | ret += buf->len; | ||
| 216 | |||
| 186 | if (pipe->inode) | 217 | if (pipe->inode) |
| 187 | do_wakeup = 1; | 218 | do_wakeup = 1; |
| 188 | 219 | ||
