* 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.
+ * Jens to support splicing to files, network, direct splicing, etc and
+ * fixing lots of bugs.
*
- * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
- * Copyright (C) 2005 Linus Torvalds <torvalds@osdl.org>
+ * Copyright (C) 2005-2006 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2005-2006 Linus Torvalds <torvalds@osdl.org>
+ * Copyright (C) 2006 Ingo Molnar <mingo@elte.hu>
*
*/
#include <linux/fs.h>
/*
* Page got truncated/unhashed. This will cause a 0-byte
- * splice, if this is the first page
+ * splice, if this is the first page.
*/
if (!page->mapping) {
err = -ENODATA;
}
/*
- * uh oh, read-error from disk
+ * Uh oh, read-error from disk.
*/
if (!PageUptodate(page)) {
err = -EIO;
}
/*
- * page is ok afterall, fall through to mapping
+ * Page is ok afterall, fall through to mapping.
*/
unlock_page(page);
}
nr_pages = PIPE_BUFFERS;
/*
- * initiate read-ahead on this page range. however, don't call into
+ * Initiate read-ahead on this page range. however, don't call into
* read-ahead if this is a non-zero offset (we are likely doing small
* chunk splice and the page is already there) for a single page.
*/
do_page_cache_readahead(mapping, in, index, nr_pages);
/*
- * now fill in the holes
+ * Now fill in the holes:
*/
error = 0;
for (i = 0; i < nr_pages; i++, index++) {
* @flags: splice modifier flags
*
* Will read pages from given file and fill them into a pipe.
- *
*/
ssize_t generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe,
size_t len, unsigned int flags)
int more;
/*
- * sub-optimal, but we are limited by the pipe ->map. we don't
+ * Sub-optimal, but we are limited by the pipe ->map. We don't
* need a kmap'ed buffer here, we just want to make sure we
* have the page pinned if the pipe page originates from the
- * page cache
+ * page cache.
*/
ptr = buf->ops->map(file, info, buf);
if (IS_ERR(ptr))
offset = sd->pos & ~PAGE_CACHE_MASK;
/*
- * reuse buf page, if SPLICE_F_MOVE is set
+ * Reuse buf page, if SPLICE_F_MOVE is set.
*/
if (sd->flags & SPLICE_F_MOVE) {
/*
if (!PageUptodate(page)) {
/*
- * page got invalidated, repeat
+ * Page got invalidated, repeat.
*/
if (!page->mapping) {
unlock_page(page);
ret += sd.len;
buf->offset += sd.len;
buf->len -= sd.len;
+
if (!buf->len) {
buf->ops = NULL;
ops->release(pipe, buf);
ret = move_from_pipe(pipe, out, len, flags, pipe_to_file);
/*
- * if file or inode is SYNC and we actually wrote some data, sync it
+ * If file or inode is SYNC and we actually wrote some data, sync it.
*/
if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(mapping->host))
&& ret > 0) {
mutex_lock(&inode->i_mutex);
err = generic_osync_inode(mapping->host, mapping,
- OSYNC_METADATA|OSYNC_DATA);
+ OSYNC_METADATA|OSYNC_DATA);
mutex_unlock(&inode->i_mutex);
if (err)
loff_t pos;
int ret;
- if (!out->f_op || !out->f_op->splice_write)
+ if (unlikely(!out->f_op || !out->f_op->splice_write))
return -EINVAL;
- if (!(out->f_mode & FMODE_WRITE))
+ if (unlikely(!(out->f_mode & FMODE_WRITE)))
return -EBADF;
pos = out->f_pos;
loff_t pos, isize, left;
int ret;
- if (!in->f_op || !in->f_op->splice_read)
+ if (unlikely(!in->f_op || !in->f_op->splice_read))
return -EINVAL;
- if (!(in->f_mode & FMODE_READ))
+ if (unlikely(!(in->f_mode & FMODE_READ)))
return -EBADF;
pos = in->f_pos;
return 0;
left = isize - in->f_pos;
- if (left < len)
+ if (unlikely(left < len))
len = left;
return in->f_op->splice_read(in, pipe, len, flags);
* 'out' and transfer the wanted data from 'in' to 'out' through that
*/
pipe = current->splice_pipe;
- if (!pipe) {
+ if (unlikely(!pipe)) {
pipe = alloc_pipe_info(NULL);
if (!pipe)
return -ENOMEM;
}
/*
- * do the splice
+ * Do the splice.
*/
ret = 0;
bytes = 0;