nfsd: nfsd should drop CAP_MKNOD for non-root
[safe/jmp/linux-2.6] / fs / splice.c
index e50a460..4ed0ba4 100644 (file)
@@ -12,7 +12,7 @@
  * Jens to support splicing to files, network, direct splicing, etc and
  * fixing lots of bugs.
  *
- * Copyright (C) 2005-2006 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2005-2006 Jens Axboe <axboe@kernel.dk>
  * Copyright (C) 2005-2006 Linus Torvalds <torvalds@osdl.org>
  * Copyright (C) 2006 Ingo Molnar <mingo@elte.hu>
  *
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/pagemap.h>
-#include <linux/pipe_fs_i.h>
+#include <linux/splice.h>
+#include <linux/memcontrol.h>
 #include <linux/mm_inline.h>
 #include <linux/swap.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
 #include <linux/module.h>
 #include <linux/syscalls.h>
-
-/*
- * Passed to the actors
- */
-struct splice_desc {
-       unsigned int len, total_len;    /* current and remaining length */
-       unsigned int flags;             /* splice flags */
-       struct file *file;              /* file to read/write */
-       loff_t pos;                     /* file position */
-};
+#include <linux/uio.h>
+#include <linux/security.h>
 
 /*
  * Attempt to steal a page from a pipe buffer. This should perhaps go into
@@ -44,45 +37,63 @@ struct splice_desc {
  * addition of remove_mapping(). If success is returned, the caller may
  * attempt to reuse this page for another destination.
  */
-static int page_cache_pipe_buf_steal(struct pipe_inode_info *info,
+static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
                                     struct pipe_buffer *buf)
 {
        struct page *page = buf->page;
-       struct address_space *mapping = page_mapping(page);
+       struct address_space *mapping;
 
-       WARN_ON(!PageLocked(page));
-       WARN_ON(!PageUptodate(page));
+       lock_page(page);
 
-       /*
-        * At least for ext2 with nobh option, we need to wait on writeback
-        * completing on this page, since we'll remove it from the pagecache.
-        * Otherwise truncate wont wait on the page, allowing the disk
-        * blocks to be reused by someone else before we actually wrote our
-        * data to them. fs corruption ensues.
-        */
-       wait_on_page_writeback(page);
+       mapping = page_mapping(page);
+       if (mapping) {
+               WARN_ON(!PageUptodate(page));
+
+               /*
+                * At least for ext2 with nobh option, we need to wait on
+                * writeback completing on this page, since we'll remove it
+                * from the pagecache.  Otherwise truncate wont wait on the
+                * page, allowing the disk blocks to be reused by someone else
+                * before we actually wrote our data to them. fs corruption
+                * ensues.
+                */
+               wait_on_page_writeback(page);
 
-       if (PagePrivate(page))
-               try_to_release_page(page, mapping_gfp_mask(mapping));
+               if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL))
+                       goto out_unlock;
 
-       if (!remove_mapping(mapping, page))
-               return 1;
+               /*
+                * If we succeeded in removing the mapping, set LRU flag
+                * and return good.
+                */
+               if (remove_mapping(mapping, page)) {
+                       buf->flags |= PIPE_BUF_FLAG_LRU;
+                       return 0;
+               }
+       }
 
-       buf->flags |= PIPE_BUF_FLAG_STOLEN | PIPE_BUF_FLAG_LRU;
-       return 0;
+       /*
+        * Raced with truncate or failed to remove page from current
+        * address space, unlock and return failure.
+        */
+out_unlock:
+       unlock_page(page);
+       return 1;
 }
 
-static void page_cache_pipe_buf_release(struct pipe_inode_info *info,
+static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe,
                                        struct pipe_buffer *buf)
 {
        page_cache_release(buf->page);
-       buf->page = NULL;
-       buf->flags &= ~(PIPE_BUF_FLAG_STOLEN | PIPE_BUF_FLAG_LRU);
+       buf->flags &= ~PIPE_BUF_FLAG_LRU;
 }
 
-static void *page_cache_pipe_buf_map(struct file *file,
-                                    struct pipe_inode_info *info,
-                                    struct pipe_buffer *buf)
+/*
+ * Check whether the contents of buf is OK to access. Since the content
+ * is a page cache page, IO may be in flight.
+ */
+static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe,
+                                      struct pipe_buffer *buf)
 {
        struct page *page = buf->page;
        int err;
@@ -108,44 +119,67 @@ static void *page_cache_pipe_buf_map(struct file *file,
                }
 
                /*
-                * Page is ok afterall, fall through to mapping.
+                * Page is ok afterall, we are done.
                 */
                unlock_page(page);
        }
 
-       return kmap(page);
+       return 0;
 error:
        unlock_page(page);
-       return ERR_PTR(err);
+       return err;
 }
 
-static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info,
-                                     struct pipe_buffer *buf)
+static const struct pipe_buf_operations page_cache_pipe_buf_ops = {
+       .can_merge = 0,
+       .map = generic_pipe_buf_map,
+       .unmap = generic_pipe_buf_unmap,
+       .confirm = page_cache_pipe_buf_confirm,
+       .release = page_cache_pipe_buf_release,
+       .steal = page_cache_pipe_buf_steal,
+       .get = generic_pipe_buf_get,
+};
+
+static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
+                                   struct pipe_buffer *buf)
 {
-       kunmap(buf->page);
+       if (!(buf->flags & PIPE_BUF_FLAG_GIFT))
+               return 1;
+
+       buf->flags |= PIPE_BUF_FLAG_LRU;
+       return generic_pipe_buf_steal(pipe, buf);
 }
 
-static struct pipe_buf_operations page_cache_pipe_buf_ops = {
+static const struct pipe_buf_operations user_page_pipe_buf_ops = {
        .can_merge = 0,
-       .map = page_cache_pipe_buf_map,
-       .unmap = page_cache_pipe_buf_unmap,
+       .map = generic_pipe_buf_map,
+       .unmap = generic_pipe_buf_unmap,
+       .confirm = generic_pipe_buf_confirm,
        .release = page_cache_pipe_buf_release,
-       .steal = page_cache_pipe_buf_steal,
+       .steal = user_page_pipe_buf_steal,
+       .get = generic_pipe_buf_get,
 };
 
-/*
- * Pipe output worker. This sets up our pipe format with the page cache
- * pipe buffer operations. Otherwise very similar to the regular pipe_writev().
+/**
+ * splice_to_pipe - fill passed data into a pipe
+ * @pipe:      pipe to fill
+ * @spd:       data to fill
+ *
+ * Description:
+ *    @spd contains a map of pages and len/offset tuples, along with
+ *    the struct pipe_buf_operations associated with these pages. This
+ *    function will link that data to the pipe.
+ *
  */
-static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages,
-                           int nr_pages, unsigned long offset,
-                           unsigned long len, unsigned int flags)
+ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
+                      struct splice_pipe_desc *spd)
 {
-       int ret, do_wakeup, i;
+       unsigned int spd_pages = spd->nr_pages;
+       int ret, do_wakeup, page_nr;
 
        ret = 0;
        do_wakeup = 0;
-       i = 0;
+       page_nr = 0;
 
        if (pipe->inode)
                mutex_lock(&pipe->inode->i_mutex);
@@ -161,27 +195,23 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages,
                if (pipe->nrbufs < PIPE_BUFFERS) {
                        int newbuf = (pipe->curbuf + pipe->nrbufs) & (PIPE_BUFFERS - 1);
                        struct pipe_buffer *buf = pipe->bufs + newbuf;
-                       struct page *page = pages[i++];
-                       unsigned long this_len;
 
-                       this_len = PAGE_CACHE_SIZE - offset;
-                       if (this_len > len)
-                               this_len = len;
+                       buf->page = spd->pages[page_nr];
+                       buf->offset = spd->partial[page_nr].offset;
+                       buf->len = spd->partial[page_nr].len;
+                       buf->private = spd->partial[page_nr].private;
+                       buf->ops = spd->ops;
+                       if (spd->flags & SPLICE_F_GIFT)
+                               buf->flags |= PIPE_BUF_FLAG_GIFT;
 
-                       buf->page = page;
-                       buf->offset = offset;
-                       buf->len = this_len;
-                       buf->ops = &page_cache_pipe_buf_ops;
                        pipe->nrbufs++;
+                       page_nr++;
+                       ret += buf->len;
+
                        if (pipe->inode)
                                do_wakeup = 1;
 
-                       ret += this_len;
-                       len -= this_len;
-                       offset = 0;
-                       if (!--nr_pages)
-                               break;
-                       if (!len)
+                       if (!--spd->nr_pages)
                                break;
                        if (pipe->nrbufs < PIPE_BUFFERS)
                                continue;
@@ -189,7 +219,7 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages,
                        break;
                }
 
-               if (flags & SPLICE_F_NONBLOCK) {
+               if (spd->flags & SPLICE_F_NONBLOCK) {
                        if (!ret)
                                ret = -EAGAIN;
                        break;
@@ -214,69 +244,78 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages,
                pipe->waiting_writers--;
        }
 
-       if (pipe->inode)
+       if (pipe->inode) {
                mutex_unlock(&pipe->inode->i_mutex);
 
-       if (do_wakeup) {
-               smp_mb();
-               if (waitqueue_active(&pipe->wait))
-                       wake_up_interruptible(&pipe->wait);
-               kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
+               if (do_wakeup) {
+                       smp_mb();
+                       if (waitqueue_active(&pipe->wait))
+                               wake_up_interruptible(&pipe->wait);
+                       kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
+               }
        }
 
-       while (i < nr_pages)
-               page_cache_release(pages[i++]);
+       while (page_nr < spd_pages)
+               spd->spd_release(spd, page_nr++);
 
        return ret;
 }
 
+static void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
+{
+       page_cache_release(spd->pages[i]);
+}
+
 static int
-__generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe,
-                          size_t len, unsigned int flags)
+__generic_file_splice_read(struct file *in, loff_t *ppos,
+                          struct pipe_inode_info *pipe, size_t len,
+                          unsigned int flags)
 {
        struct address_space *mapping = in->f_mapping;
-       unsigned int offset, nr_pages;
+       unsigned int loff, nr_pages, req_pages;
        struct page *pages[PIPE_BUFFERS];
+       struct partial_page partial[PIPE_BUFFERS];
        struct page *page;
-       pgoff_t index;
-       int i, error;
-
-       index = in->f_pos >> PAGE_CACHE_SHIFT;
-       offset = in->f_pos & ~PAGE_CACHE_MASK;
-       nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
-       if (nr_pages > PIPE_BUFFERS)
-               nr_pages = PIPE_BUFFERS;
+       pgoff_t index, end_index;
+       loff_t isize;
+       int error, page_nr;
+       struct splice_pipe_desc spd = {
+               .pages = pages,
+               .partial = partial,
+               .flags = flags,
+               .ops = &page_cache_pipe_buf_ops,
+               .spd_release = spd_release_page,
+       };
+
+       index = *ppos >> PAGE_CACHE_SHIFT;
+       loff = *ppos & ~PAGE_CACHE_MASK;
+       req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       nr_pages = min(req_pages, (unsigned)PIPE_BUFFERS);
 
        /*
-        * 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.
+        * Lookup the (hopefully) full range of pages we need.
         */
-       if (!offset || nr_pages > 1)
-               do_page_cache_readahead(mapping, in, index, nr_pages);
+       spd.nr_pages = find_get_pages_contig(mapping, index, nr_pages, pages);
+       index += spd.nr_pages;
 
        /*
-        * Now fill in the holes:
+        * If find_get_pages_contig() returned fewer pages than we needed,
+        * readahead/allocate the rest and fill in the holes.
         */
+       if (spd.nr_pages < nr_pages)
+               page_cache_sync_readahead(mapping, &in->f_ra, in,
+                               index, req_pages - spd.nr_pages);
+
        error = 0;
-       for (i = 0; i < nr_pages; i++, index++) {
-find_page:
+       while (spd.nr_pages < nr_pages) {
                /*
-                * lookup the page for this index
+                * Page could be there, find_get_pages_contig() breaks on
+                * the first hole.
                 */
                page = find_get_page(mapping, index);
                if (!page) {
                        /*
-                        * If in nonblock mode then dont block on
-                        * readpage (we've kicked readahead so there
-                        * will be asynchronous progress):
-                        */
-                       if (flags & SPLICE_F_NONBLOCK)
-                               break;
-
-                       /*
-                        * page didn't exist, allocate one
+                        * page didn't exist, allocate one.
                         */
                        page = page_cache_alloc_cold(mapping);
                        if (!page)
@@ -286,27 +325,77 @@ find_page:
                                                mapping_gfp_mask(mapping));
                        if (unlikely(error)) {
                                page_cache_release(page);
+                               if (error == -EEXIST)
+                                       continue;
                                break;
                        }
-
-                       goto readpage;
+                       /*
+                        * add_to_page_cache() locks the page, unlock it
+                        * to avoid convoluting the logic below even more.
+                        */
+                       unlock_page(page);
                }
 
+               pages[spd.nr_pages++] = page;
+               index++;
+       }
+
+       /*
+        * Now loop over the map and see if we need to start IO on any
+        * pages, fill in the partial map, etc.
+        */
+       index = *ppos >> PAGE_CACHE_SHIFT;
+       nr_pages = spd.nr_pages;
+       spd.nr_pages = 0;
+       for (page_nr = 0; page_nr < nr_pages; page_nr++) {
+               unsigned int this_len;
+
+               if (!len)
+                       break;
+
+               /*
+                * this_len is the max we'll use from this page
+                */
+               this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
+               page = pages[page_nr];
+
+               if (PageReadahead(page))
+                       page_cache_async_readahead(mapping, &in->f_ra, in,
+                                       page, index, req_pages - page_nr);
+
                /*
                 * If the page isn't uptodate, we may need to start io on it
                 */
                if (!PageUptodate(page)) {
-                       lock_page(page);
+                       /*
+                        * If in nonblock mode then dont block on waiting
+                        * for an in-flight io page
+                        */
+                       if (flags & SPLICE_F_NONBLOCK) {
+                               if (!trylock_page(page)) {
+                                       error = -EAGAIN;
+                                       break;
+                               }
+                       } else
+                               lock_page(page);
 
                        /*
-                        * page was truncated, stop here. if this isn't the
-                        * first page, we'll just complete what we already
-                        * added
+                        * Page was truncated, or invalidated by the
+                        * filesystem.  Redo the find/create, but this time the
+                        * page is kept locked, so there's no chance of another
+                        * race with truncate/invalidate.
                         */
                        if (!page->mapping) {
                                unlock_page(page);
-                               page_cache_release(page);
-                               break;
+                               page = find_or_create_page(mapping, index,
+                                               mapping_gfp_mask(mapping));
+
+                               if (!page) {
+                                       error = -ENOMEM;
+                                       break;
+                               }
+                               page_cache_release(pages[page_nr]);
+                               pages[page_nr] = page;
                        }
                        /*
                         * page was already under io and is now done, great
@@ -316,25 +405,71 @@ find_page:
                                goto fill_it;
                        }
 
-readpage:
                        /*
                         * need to read in the page
                         */
                        error = mapping->a_ops->readpage(in, page);
-
                        if (unlikely(error)) {
-                               page_cache_release(page);
+                               /*
+                                * We really should re-lookup the page here,
+                                * but it complicates things a lot. Instead
+                                * lets just do what we already stored, and
+                                * we'll get it the next time we are called.
+                                */
                                if (error == AOP_TRUNCATED_PAGE)
-                                       goto find_page;
+                                       error = 0;
+
                                break;
                        }
                }
 fill_it:
-               pages[i] = page;
+               /*
+                * i_size must be checked after PageUptodate.
+                */
+               isize = i_size_read(mapping->host);
+               end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
+               if (unlikely(!isize || index > end_index))
+                       break;
+
+               /*
+                * if this is the last page, see if we need to shrink
+                * the length and stop
+                */
+               if (end_index == index) {
+                       unsigned int plen;
+
+                       /*
+                        * max good bytes in this page
+                        */
+                       plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
+                       if (plen <= loff)
+                               break;
+
+                       /*
+                        * force quit after adding this page
+                        */
+                       this_len = min(this_len, plen - loff);
+                       len = this_len;
+               }
+
+               partial[page_nr].offset = loff;
+               partial[page_nr].len = this_len;
+               len -= this_len;
+               loff = 0;
+               spd.nr_pages++;
+               index++;
        }
 
-       if (i)
-               return move_to_pipe(pipe, pages, i, offset, len, flags);
+       /*
+        * Release any pages at the end, if we quit early. 'page_nr' is how far
+        * we got, 'nr_pages' is how many pages are in the map.
+        */
+       while (page_nr < nr_pages)
+               page_cache_release(pages[page_nr++]);
+       in->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
+
+       if (spd.nr_pages)
+               return splice_to_pipe(pipe, &spd);
 
        return error;
 }
@@ -342,39 +477,35 @@ fill_it:
 /**
  * generic_file_splice_read - splice data from file to a pipe
  * @in:                file to splice from
+ * @ppos:      position in @in
  * @pipe:      pipe to splice to
  * @len:       number of bytes to splice
  * @flags:     splice modifier flags
  *
- * Will read pages from given file and fill them into a pipe.
+ * Description:
+ *    Will read pages from given file and fill them into a pipe. Can be
+ *    used as long as the address_space operations for the source implements
+ *    a readpage() hook.
+ *
  */
-ssize_t generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe,
-                                size_t len, unsigned int flags)
+ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
+                                struct pipe_inode_info *pipe, size_t len,
+                                unsigned int flags)
 {
-       ssize_t spliced;
+       loff_t isize, left;
        int ret;
 
-       ret = 0;
-       spliced = 0;
-
-       while (len) {
-               ret = __generic_file_splice_read(in, pipe, len, flags);
-
-               if (ret <= 0)
-                       break;
-
-               in->f_pos += ret;
-               len -= ret;
-               spliced += ret;
+       isize = i_size_read(in->f_mapping->host);
+       if (unlikely(*ppos >= isize))
+               return 0;
 
-               if (!(flags & SPLICE_F_NONBLOCK))
-                       continue;
-               ret = -EAGAIN;
-               break;
-       }
+       left = isize - *ppos;
+       if (unlikely(left < len))
+               len = left;
 
-       if (spliced)
-               return spliced;
+       ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
+       if (ret > 0)
+               *ppos += ret;
 
        return ret;
 }
@@ -383,38 +514,24 @@ EXPORT_SYMBOL(generic_file_splice_read);
 
 /*
  * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
- * using sendpage().
+ * using sendpage(). Return the number of bytes sent.
  */
-static int pipe_to_sendpage(struct pipe_inode_info *info,
+static int pipe_to_sendpage(struct pipe_inode_info *pipe,
                            struct pipe_buffer *buf, struct splice_desc *sd)
 {
-       struct file *file = sd->file;
+       struct file *file = sd->u.file;
        loff_t pos = sd->pos;
-       unsigned int offset;
-       ssize_t ret;
-       void *ptr;
-       int more;
-
-       /*
-        * 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.
-        */
-       ptr = buf->ops->map(file, info, buf);
-       if (IS_ERR(ptr))
-               return PTR_ERR(ptr);
+       int ret, more;
 
-       offset = pos & ~PAGE_CACHE_MASK;
-       more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
+       ret = buf->ops->confirm(pipe, buf);
+       if (!ret) {
+               more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
 
-       ret = file->f_op->sendpage(file, buf->page, offset, sd->len, &pos,more);
-
-       buf->ops->unmap(info, buf);
-       if (ret == sd->len)
-               return 0;
+               ret = file->f_op->sendpage(file, buf->page, buf->offset,
+                                          sd->len, &pos, more);
+       }
 
-       return -EIO;
+       return ret;
 }
 
 /*
@@ -437,167 +554,99 @@ static int pipe_to_sendpage(struct pipe_inode_info *info,
  * SPLICE_F_MOVE isn't set, or we cannot move the page, we simply create
  * a new page in the output file page cache and fill/dirty that.
  */
-static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
+static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
                        struct splice_desc *sd)
 {
-       struct file *file = sd->file;
+       struct file *file = sd->u.file;
        struct address_space *mapping = file->f_mapping;
-       gfp_t gfp_mask = mapping_gfp_mask(mapping);
-       unsigned int offset;
+       unsigned int offset, this_len;
        struct page *page;
-       pgoff_t index;
-       char *src;
+       void *fsdata;
        int ret;
 
        /*
         * make sure the data in this buffer is uptodate
         */
-       src = buf->ops->map(file, info, buf);
-       if (IS_ERR(src))
-               return PTR_ERR(src);
+       ret = buf->ops->confirm(pipe, buf);
+       if (unlikely(ret))
+               return ret;
 
-       index = sd->pos >> PAGE_CACHE_SHIFT;
        offset = sd->pos & ~PAGE_CACHE_MASK;
 
-       /*
-        * Reuse buf page, if SPLICE_F_MOVE is set.
-        */
-       if (sd->flags & SPLICE_F_MOVE) {
-               /*
-                * If steal succeeds, buf->page is now pruned from the vm
-                * side (LRU and page cache) and we can reuse it.
-                */
-               if (buf->ops->steal(info, buf))
-                       goto find_page;
+       this_len = sd->len;
+       if (this_len + offset > PAGE_CACHE_SIZE)
+               this_len = PAGE_CACHE_SIZE - offset;
 
-               /*
-                * this will also set the page locked
-                */
-               page = buf->page;
-               if (add_to_page_cache(page, mapping, index, gfp_mask))
-                       goto find_page;
-
-               if (!(buf->flags & PIPE_BUF_FLAG_LRU))
-                       lru_cache_add(page);
-       } else {
-find_page:
-               ret = -ENOMEM;
-               page = find_or_create_page(mapping, index, gfp_mask);
-               if (!page)
-                       goto out_nomem;
+       ret = pagecache_write_begin(file, mapping, sd->pos, this_len,
+                               AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata);
+       if (unlikely(ret))
+               goto out;
 
+       if (buf->page != page) {
                /*
-                * If the page is uptodate, it is also locked. If it isn't
-                * uptodate, we can mark it uptodate if we are filling the
-                * full page. Otherwise we need to read it in first...
+                * Careful, ->map() uses KM_USER0!
                 */
-               if (!PageUptodate(page)) {
-                       if (sd->len < PAGE_CACHE_SIZE) {
-                               ret = mapping->a_ops->readpage(file, page);
-                               if (unlikely(ret))
-                                       goto out;
-
-                               lock_page(page);
-
-                               if (!PageUptodate(page)) {
-                                       /*
-                                        * Page got invalidated, repeat.
-                                        */
-                                       if (!page->mapping) {
-                                               unlock_page(page);
-                                               page_cache_release(page);
-                                               goto find_page;
-                                       }
-                                       ret = -EIO;
-                                       goto out;
-                               }
-                       } else {
-                               WARN_ON(!PageLocked(page));
-                               SetPageUptodate(page);
-                       }
-               }
-       }
-
-       ret = mapping->a_ops->prepare_write(file, page, 0, sd->len);
-       if (ret == AOP_TRUNCATED_PAGE) {
-               page_cache_release(page);
-               goto find_page;
-       } else if (ret)
-               goto out;
-
-       if (!(buf->flags & PIPE_BUF_FLAG_STOLEN)) {
-               char *dst = kmap_atomic(page, KM_USER0);
+               char *src = buf->ops->map(pipe, buf, 1);
+               char *dst = kmap_atomic(page, KM_USER1);
 
-               memcpy(dst + offset, src + buf->offset, sd->len);
+               memcpy(dst + offset, src + buf->offset, this_len);
                flush_dcache_page(page);
-               kunmap_atomic(dst, KM_USER0);
+               kunmap_atomic(dst, KM_USER1);
+               buf->ops->unmap(pipe, buf, src);
        }
-
-       ret = mapping->a_ops->commit_write(file, page, 0, sd->len);
-       if (ret == AOP_TRUNCATED_PAGE) {
-               page_cache_release(page);
-               goto find_page;
-       } else if (ret)
-               goto out;
-
-       mark_page_accessed(page);
-       balance_dirty_pages_ratelimited(mapping);
+       ret = pagecache_write_end(file, mapping, sd->pos, this_len, this_len,
+                               page, fsdata);
 out:
-       if (!(buf->flags & PIPE_BUF_FLAG_STOLEN)) {
-               page_cache_release(page);
-               unlock_page(page);
-       }
-out_nomem:
-       buf->ops->unmap(info, buf);
        return ret;
 }
 
-typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *,
-                          struct splice_desc *);
-
-/*
- * Pipe input worker. Most of this logic works like a regular pipe, the
- * key here is the 'actor' worker passed in that actually moves the data
- * to the wanted destination. See pipe_to_file/pipe_to_sendpage above.
+/**
+ * __splice_from_pipe - splice data from a pipe to given actor
+ * @pipe:      pipe to splice from
+ * @sd:                information to @actor
+ * @actor:     handler that splices the data
+ *
+ * Description:
+ *    This function does little more than loop over the pipe and call
+ *    @actor to do the actual moving of a single struct pipe_buffer to
+ *    the desired destination. See pipe_to_file, pipe_to_sendpage, or
+ *    pipe_to_user.
+ *
  */
-static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out,
-                             size_t len, unsigned int flags,
-                             splice_actor *actor)
+ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
+                          splice_actor *actor)
 {
        int ret, do_wakeup, err;
-       struct splice_desc sd;
 
        ret = 0;
        do_wakeup = 0;
 
-       sd.total_len = len;
-       sd.flags = flags;
-       sd.file = out;
-       sd.pos = out->f_pos;
-
-       if (pipe->inode)
-               mutex_lock(&pipe->inode->i_mutex);
-
        for (;;) {
                if (pipe->nrbufs) {
                        struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
-                       struct pipe_buf_operations *ops = buf->ops;
+                       const struct pipe_buf_operations *ops = buf->ops;
 
-                       sd.len = buf->len;
-                       if (sd.len > sd.total_len)
-                               sd.len = sd.total_len;
+                       sd->len = buf->len;
+                       if (sd->len > sd->total_len)
+                               sd->len = sd->total_len;
 
-                       err = actor(pipe, buf, &sd);
-                       if (err) {
+                       err = actor(pipe, buf, sd);
+                       if (err <= 0) {
                                if (!ret && err != -ENODATA)
                                        ret = err;
 
                                break;
                        }
 
-                       ret += sd.len;
-                       buf->offset += sd.len;
-                       buf->len -= sd.len;
+                       ret += err;
+                       buf->offset += err;
+                       buf->len -= err;
+
+                       sd->len -= err;
+                       sd->pos += err;
+                       sd->total_len -= err;
+                       if (sd->len)
+                               continue;
 
                        if (!buf->len) {
                                buf->ops = NULL;
@@ -608,9 +657,7 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out,
                                        do_wakeup = 1;
                        }
 
-                       sd.pos += sd.len;
-                       sd.total_len -= sd.len;
-                       if (!sd.total_len)
+                       if (!sd->total_len)
                                break;
                }
 
@@ -623,7 +670,7 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out,
                                break;
                }
 
-               if (flags & SPLICE_F_NONBLOCK) {
+               if (sd->flags & SPLICE_F_NONBLOCK) {
                        if (!ret)
                                ret = -EAGAIN;
                        break;
@@ -646,9 +693,6 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out,
                pipe_wait(pipe);
        }
 
-       if (pipe->inode)
-               mutex_unlock(&pipe->inode->i_mutex);
-
        if (do_wakeup) {
                smp_mb();
                if (waitqueue_active(&pipe->wait))
@@ -656,46 +700,163 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out,
                kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
        }
 
-       out->f_pos = sd.pos;
        return ret;
+}
+EXPORT_SYMBOL(__splice_from_pipe);
+
+/**
+ * splice_from_pipe - splice data from a pipe to a file
+ * @pipe:      pipe to splice from
+ * @out:       file to splice to
+ * @ppos:      position in @out
+ * @len:       how many bytes to splice
+ * @flags:     splice modifier flags
+ * @actor:     handler that splices the data
+ *
+ * Description:
+ *    See __splice_from_pipe. This function locks the input and output inodes,
+ *    otherwise it's identical to __splice_from_pipe().
+ *
+ */
+ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
+                        loff_t *ppos, size_t len, unsigned int flags,
+                        splice_actor *actor)
+{
+       ssize_t ret;
+       struct inode *inode = out->f_mapping->host;
+       struct splice_desc sd = {
+               .total_len = len,
+               .flags = flags,
+               .pos = *ppos,
+               .u.file = out,
+       };
+
+       /*
+        * The actor worker might be calling ->write_begin and
+        * ->write_end. Most of the time, these expect i_mutex to
+        * be held. Since this may result in an ABBA deadlock with
+        * pipe->inode, we have to order lock acquiry here.
+        */
+       inode_double_lock(inode, pipe->inode);
+       ret = __splice_from_pipe(pipe, &sd, actor);
+       inode_double_unlock(inode, pipe->inode);
+
+       return ret;
+}
+
+/**
+ * generic_file_splice_write_nolock - generic_file_splice_write without mutexes
+ * @pipe:      pipe info
+ * @out:       file to write to
+ * @ppos:      position in @out
+ * @len:       number of bytes to splice
+ * @flags:     splice modifier flags
+ *
+ * Description:
+ *    Will either move or copy pages (determined by @flags options) from
+ *    the given pipe inode to the given file. The caller is responsible
+ *    for acquiring i_mutex on both inodes.
+ *
+ */
+ssize_t
+generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
+                                loff_t *ppos, size_t len, unsigned int flags)
+{
+       struct address_space *mapping = out->f_mapping;
+       struct inode *inode = mapping->host;
+       struct splice_desc sd = {
+               .total_len = len,
+               .flags = flags,
+               .pos = *ppos,
+               .u.file = out,
+       };
+       ssize_t ret;
+       int err;
+
+       err = file_remove_suid(out);
+       if (unlikely(err))
+               return err;
+
+       ret = __splice_from_pipe(pipe, &sd, pipe_to_file);
+       if (ret > 0) {
+               unsigned long nr_pages;
+
+               *ppos += ret;
+               nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+               /*
+                * If file or inode is SYNC and we actually wrote some data,
+                * sync it.
+                */
+               if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
+                       err = generic_osync_inode(inode, mapping,
+                                                 OSYNC_METADATA|OSYNC_DATA);
 
+                       if (err)
+                               ret = err;
+               }
+               balance_dirty_pages_ratelimited_nr(mapping, nr_pages);
+       }
+
+       return ret;
 }
 
+EXPORT_SYMBOL(generic_file_splice_write_nolock);
+
 /**
  * generic_file_splice_write - splice data from a pipe to a file
  * @pipe:      pipe info
  * @out:       file to write to
+ * @ppos:      position in @out
  * @len:       number of bytes to splice
  * @flags:     splice modifier flags
  *
- * Will either move or copy pages (determined by @flags options) from
- * the given pipe inode to the given file.
+ * Description:
+ *    Will either move or copy pages (determined by @flags options) from
+ *    the given pipe inode to the given file.
  *
  */
 ssize_t
 generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
-                         size_t len, unsigned int flags)
+                         loff_t *ppos, size_t len, unsigned int flags)
 {
        struct address_space *mapping = out->f_mapping;
+       struct inode *inode = mapping->host;
+       struct splice_desc sd = {
+               .total_len = len,
+               .flags = flags,
+               .pos = *ppos,
+               .u.file = out,
+       };
        ssize_t ret;
 
-       ret = move_from_pipe(pipe, out, len, flags, pipe_to_file);
+       inode_double_lock(inode, pipe->inode);
+       ret = file_remove_suid(out);
+       if (likely(!ret))
+               ret = __splice_from_pipe(pipe, &sd, pipe_to_file);
+       inode_double_unlock(inode, pipe->inode);
+       if (ret > 0) {
+               unsigned long nr_pages;
 
-       /*
-        * 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) {
-               struct inode *inode = mapping->host;
-               int err;
-
-               mutex_lock(&inode->i_mutex);
-               err = generic_osync_inode(mapping->host, mapping,
-                                         OSYNC_METADATA|OSYNC_DATA);
-               mutex_unlock(&inode->i_mutex);
-
-               if (err)
-                       ret = err;
+               *ppos += ret;
+               nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+               /*
+                * If file or inode is SYNC and we actually wrote some data,
+                * sync it.
+                */
+               if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
+                       int err;
+
+                       mutex_lock(&inode->i_mutex);
+                       err = generic_osync_inode(inode, mapping,
+                                                 OSYNC_METADATA|OSYNC_DATA);
+                       mutex_unlock(&inode->i_mutex);
+
+                       if (err)
+                               ret = err;
+               }
+               balance_dirty_pages_ratelimited_nr(mapping, nr_pages);
        }
 
        return ret;
@@ -705,19 +866,21 @@ EXPORT_SYMBOL(generic_file_splice_write);
 
 /**
  * generic_splice_sendpage - splice data from a pipe to a socket
- * @inode:     pipe inode
+ * @pipe:      pipe to splice from
  * @out:       socket to write to
+ * @ppos:      position in @out
  * @len:       number of bytes to splice
  * @flags:     splice modifier flags
  *
- * Will send @len bytes from the pipe to a network socket. No data copying
- * is involved.
+ * Description:
+ *    Will send @len bytes from the pipe to a network socket. No data copying
+ *    is involved.
  *
  */
 ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out,
-                               size_t len, unsigned int flags)
+                               loff_t *ppos, size_t len, unsigned int flags)
 {
-       return move_from_pipe(pipe, out, len, flags, pipe_to_sendpage);
+       return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage);
 }
 
 EXPORT_SYMBOL(generic_splice_sendpage);
@@ -726,9 +889,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
  * Attempt to initiate a splice from pipe to file.
  */
 static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
-                          size_t len, unsigned int flags)
+                          loff_t *ppos, size_t len, unsigned int flags)
 {
-       loff_t pos;
        int ret;
 
        if (unlikely(!out->f_op || !out->f_op->splice_write))
@@ -737,22 +899,23 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
        if (unlikely(!(out->f_mode & FMODE_WRITE)))
                return -EBADF;
 
-       pos = out->f_pos;
+       if (unlikely(out->f_flags & O_APPEND))
+               return -EINVAL;
 
-       ret = rw_verify_area(WRITE, out, &pos, len);
+       ret = rw_verify_area(WRITE, out, ppos, len);
        if (unlikely(ret < 0))
                return ret;
 
-       return out->f_op->splice_write(pipe, out, len, flags);
+       return out->f_op->splice_write(pipe, out, ppos, len, flags);
 }
 
 /*
  * Attempt to initiate a splice from a file to a pipe.
  */
-static long do_splice_to(struct file *in, struct pipe_inode_info *pipe,
-                        size_t len, unsigned int flags)
+static long do_splice_to(struct file *in, loff_t *ppos,
+                        struct pipe_inode_info *pipe, size_t len,
+                        unsigned int flags)
 {
-       loff_t pos, isize, left;
        int ret;
 
        if (unlikely(!in->f_op || !in->f_op->splice_read))
@@ -761,37 +924,41 @@ static long do_splice_to(struct file *in, struct pipe_inode_info *pipe,
        if (unlikely(!(in->f_mode & FMODE_READ)))
                return -EBADF;
 
-       pos = in->f_pos;
-
-       ret = rw_verify_area(READ, in, &pos, len);
+       ret = rw_verify_area(READ, in, ppos, len);
        if (unlikely(ret < 0))
                return ret;
 
-       isize = i_size_read(in->f_mapping->host);
-       if (unlikely(in->f_pos >= isize))
-               return 0;
-       
-       left = isize - in->f_pos;
-       if (unlikely(left < len))
-               len = left;
-
-       return in->f_op->splice_read(in, pipe, len, flags);
+       return in->f_op->splice_read(in, ppos, pipe, len, flags);
 }
 
-long do_splice_direct(struct file *in, struct file *out, size_t len,
-                     unsigned int flags)
+/**
+ * splice_direct_to_actor - splices data directly between two non-pipes
+ * @in:                file to splice from
+ * @sd:                actor information on where to splice to
+ * @actor:     handles the data splicing
+ *
+ * Description:
+ *    This is a special case helper to splice directly between two
+ *    points, without requiring an explicit pipe. Internally an allocated
+ *    pipe is cached in the process, and reused during the lifetime of
+ *    that process.
+ *
+ */
+ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
+                              splice_direct_actor *actor)
 {
        struct pipe_inode_info *pipe;
        long ret, bytes;
        umode_t i_mode;
-       int i;
+       size_t len;
+       int i, flags;
 
        /*
         * We require the input being a regular file, as we don't want to
         * randomly drop data for eg socket -> socket splicing. Use the
         * piped splicing for that!
         */
-       i_mode = in->f_dentry->d_inode->i_mode;
+       i_mode = in->f_path.dentry->d_inode->i_mode;
        if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode)))
                return -EINVAL;
 
@@ -807,7 +974,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len,
 
                /*
                 * We don't have an immediate reader, but we'll read the stuff
-                * out of the pipe right after the move_to_pipe(). So set
+                * out of the pipe right after the splice_to_pipe(). So set
                 * PIPE_READERS appropriately.
                 */
                pipe->readers = 1;
@@ -820,48 +987,49 @@ long do_splice_direct(struct file *in, struct file *out, size_t len,
         */
        ret = 0;
        bytes = 0;
+       len = sd->total_len;
+       flags = sd->flags;
 
-       while (len) {
-               size_t read_len, max_read_len;
+       /*
+        * Don't block on output, we have to drain the direct pipe.
+        */
+       sd->flags &= ~SPLICE_F_NONBLOCK;
 
-               /*
-                * Do at most PIPE_BUFFERS pages worth of transfer:
-                */
-               max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE));
+       while (len) {
+               size_t read_len;
+               loff_t pos = sd->pos, prev_pos = pos;
 
-               ret = do_splice_to(in, pipe, max_read_len, flags);
-               if (unlikely(ret < 0))
+               ret = do_splice_to(in, &pos, pipe, len, flags);
+               if (unlikely(ret <= 0))
                        goto out_release;
 
                read_len = ret;
+               sd->total_len = read_len;
 
                /*
                 * NOTE: nonblocking mode only applies to the input. We
                 * must not do the output in nonblocking mode as then we
                 * could get stuck data in the internal pipe:
                 */
-               ret = do_splice_from(pipe, out, read_len,
-                                    flags & ~SPLICE_F_NONBLOCK);
-               if (unlikely(ret < 0))
+               ret = actor(pipe, sd);
+               if (unlikely(ret <= 0)) {
+                       sd->pos = prev_pos;
                        goto out_release;
+               }
 
                bytes += ret;
                len -= ret;
+               sd->pos = pos;
 
-               /*
-                * In nonblocking mode, if we got back a short read then
-                * that was due to either an IO error or due to the
-                * pagecache entry not being there. In the IO error case
-                * the _next_ splice attempt will produce a clean IO error
-                * return value (not a short read), so in both cases it's
-                * correct to break out of the loop here:
-                */
-               if ((flags & SPLICE_F_NONBLOCK) && (read_len < max_read_len))
-                       break;
+               if (ret < read_len) {
+                       sd->pos = prev_pos + ret;
+                       goto out_release;
+               }
        }
 
+done:
        pipe->nrbufs = pipe->curbuf = 0;
-
+       file_accessed(in);
        return bytes;
 
 out_release:
@@ -877,63 +1045,425 @@ out_release:
                        buf->ops = NULL;
                }
        }
-       pipe->nrbufs = pipe->curbuf = 0;
 
-       /*
-        * If we transferred some data, return the number of bytes:
-        */
-       if (bytes > 0)
-               return bytes;
+       if (!bytes)
+               bytes = ret;
 
-       return ret;
+       goto done;
 }
+EXPORT_SYMBOL(splice_direct_to_actor);
 
-EXPORT_SYMBOL(do_splice_direct);
+static int direct_splice_actor(struct pipe_inode_info *pipe,
+                              struct splice_desc *sd)
+{
+       struct file *file = sd->u.file;
 
-/*
- * Determine where to splice to/from.
+       return do_splice_from(pipe, file, &sd->pos, sd->total_len, sd->flags);
+}
+
+/**
+ * do_splice_direct - splices data directly between two files
+ * @in:                file to splice from
+ * @ppos:      input file offset
+ * @out:       file to splice to
+ * @len:       number of bytes to splice
+ * @flags:     splice modifier flags
+ *
+ * Description:
+ *    For use by do_sendfile(). splice can easily emulate sendfile, but
+ *    doing it in the application would incur an extra system call
+ *    (splice in + splice out, as compared to just sendfile()). So this helper
+ *    can splice directly through a process-private pipe.
+ *
  */
-static long do_splice(struct file *in, loff_t __user *off_in,
-                     struct file *out, loff_t __user *off_out,
+long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
                      size_t len, unsigned int flags)
 {
-       struct pipe_inode_info *pipe;
+       struct splice_desc sd = {
+               .len            = len,
+               .total_len      = len,
+               .flags          = flags,
+               .pos            = *ppos,
+               .u.file         = out,
+       };
+       long ret;
+
+       ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
+       if (ret > 0)
+               *ppos = sd.pos;
 
-       pipe = in->f_dentry->d_inode->i_pipe;
+       return ret;
+}
+
+/*
+ * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same
+ * location, so checking ->i_pipe is not enough to verify that this is a
+ * pipe.
+ */
+static inline struct pipe_inode_info *pipe_info(struct inode *inode)
+{
+       if (S_ISFIFO(inode->i_mode))
+               return inode->i_pipe;
+
+       return NULL;
+}
+
+/*
+ * Determine where to splice to/from.
+ */
+static long do_splice(struct file *in, loff_t __user *off_in,
+                     struct file *out, loff_t __user *off_out,
+                     size_t len, unsigned int flags)
+{
+       struct pipe_inode_info *pipe;
+       loff_t offset, *off;
+       long ret;
+
+       pipe = pipe_info(in->f_path.dentry->d_inode);
        if (pipe) {
                if (off_in)
                        return -ESPIPE;
                if (off_out) {
                        if (out->f_op->llseek == no_llseek)
                                return -EINVAL;
-                       if (copy_from_user(&out->f_pos, off_out,
-                                          sizeof(loff_t)))
+                       if (copy_from_user(&offset, off_out, sizeof(loff_t)))
                                return -EFAULT;
-               }
+                       off = &offset;
+               } else
+                       off = &out->f_pos;
 
-               return do_splice_from(pipe, out, len, flags);
+               ret = do_splice_from(pipe, out, off, len, flags);
+
+               if (off_out && copy_to_user(off_out, off, sizeof(loff_t)))
+                       ret = -EFAULT;
+
+               return ret;
        }
 
-       pipe = out->f_dentry->d_inode->i_pipe;
+       pipe = pipe_info(out->f_path.dentry->d_inode);
        if (pipe) {
                if (off_out)
                        return -ESPIPE;
                if (off_in) {
                        if (in->f_op->llseek == no_llseek)
                                return -EINVAL;
-                       if (copy_from_user(&in->f_pos, off_in, sizeof(loff_t)))
+                       if (copy_from_user(&offset, off_in, sizeof(loff_t)))
                                return -EFAULT;
-               }
+                       off = &offset;
+               } else
+                       off = &in->f_pos;
+
+               ret = do_splice_to(in, off, pipe, len, flags);
 
-               return do_splice_to(in, pipe, len, flags);
+               if (off_in && copy_to_user(off_in, off, sizeof(loff_t)))
+                       ret = -EFAULT;
+
+               return ret;
        }
 
        return -EINVAL;
 }
 
-asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
-                          int fd_out, loff_t __user *off_out,
-                          size_t len, unsigned int flags)
+/*
+ * Map an iov into an array of pages and offset/length tupples. With the
+ * partial_page structure, we can map several non-contiguous ranges into
+ * our ones pages[] map instead of splitting that operation into pieces.
+ * Could easily be exported as a generic helper for other users, in which
+ * case one would probably want to add a 'max_nr_pages' parameter as well.
+ */
+static int get_iovec_page_array(const struct iovec __user *iov,
+                               unsigned int nr_vecs, struct page **pages,
+                               struct partial_page *partial, int aligned)
+{
+       int buffers = 0, error = 0;
+
+       while (nr_vecs) {
+               unsigned long off, npages;
+               struct iovec entry;
+               void __user *base;
+               size_t len;
+               int i;
+
+               error = -EFAULT;
+               if (copy_from_user(&entry, iov, sizeof(entry)))
+                       break;
+
+               base = entry.iov_base;
+               len = entry.iov_len;
+
+               /*
+                * Sanity check this iovec. 0 read succeeds.
+                */
+               error = 0;
+               if (unlikely(!len))
+                       break;
+               error = -EFAULT;
+               if (!access_ok(VERIFY_READ, base, len))
+                       break;
+
+               /*
+                * Get this base offset and number of pages, then map
+                * 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;
+
+               error = get_user_pages_fast((unsigned long)base, npages,
+                                       0, &pages[buffers]);
+
+               if (unlikely(error <= 0))
+                       break;
+
+               /*
+                * Fill this contiguous range into the partial page map.
+                */
+               for (i = 0; i < error; i++) {
+                       const int plen = min_t(size_t, len, PAGE_SIZE - off);
+
+                       partial[buffers].offset = off;
+                       partial[buffers].len = plen;
+
+                       off = 0;
+                       len -= plen;
+                       buffers++;
+               }
+
+               /*
+                * We didn't complete this iov, stop here since it probably
+                * means we have to move some of this into a pipe to
+                * be able to continue.
+                */
+               if (len)
+                       break;
+
+               /*
+                * Don't continue if we mapped fewer pages than we asked for,
+                * or if we mapped the max number of pages that we have
+                * room for.
+                */
+               if (error < npages || buffers == PIPE_BUFFERS)
+                       break;
+
+               nr_vecs--;
+               iov++;
+       }
+
+       if (buffers)
+               return buffers;
+
+       return error;
+}
+
+static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
+                       struct splice_desc *sd)
+{
+       char *src;
+       int ret;
+
+       ret = buf->ops->confirm(pipe, buf);
+       if (unlikely(ret))
+               return ret;
+
+       /*
+        * See if we can use the atomic maps, by prefaulting in the
+        * pages and doing an atomic copy
+        */
+       if (!fault_in_pages_writeable(sd->u.userptr, sd->len)) {
+               src = buf->ops->map(pipe, buf, 1);
+               ret = __copy_to_user_inatomic(sd->u.userptr, src + buf->offset,
+                                                       sd->len);
+               buf->ops->unmap(pipe, buf, src);
+               if (!ret) {
+                       ret = sd->len;
+                       goto out;
+               }
+       }
+
+       /*
+        * No dice, use slow non-atomic map and copy
+        */
+       src = buf->ops->map(pipe, buf, 0);
+
+       ret = sd->len;
+       if (copy_to_user(sd->u.userptr, src + buf->offset, sd->len))
+               ret = -EFAULT;
+
+       buf->ops->unmap(pipe, buf, src);
+out:
+       if (ret > 0)
+               sd->u.userptr += ret;
+       return ret;
+}
+
+/*
+ * For lack of a better implementation, implement vmsplice() to userspace
+ * as a simple copy of the pipes pages to the user iov.
+ */
+static long vmsplice_to_user(struct file *file, const struct iovec __user *iov,
+                            unsigned long nr_segs, unsigned int flags)
+{
+       struct pipe_inode_info *pipe;
+       struct splice_desc sd;
+       ssize_t size;
+       int error;
+       long ret;
+
+       pipe = pipe_info(file->f_path.dentry->d_inode);
+       if (!pipe)
+               return -EBADF;
+
+       if (pipe->inode)
+               mutex_lock(&pipe->inode->i_mutex);
+
+       error = ret = 0;
+       while (nr_segs) {
+               void __user *base;
+               size_t len;
+
+               /*
+                * Get user address base and length for this iovec.
+                */
+               error = get_user(base, &iov->iov_base);
+               if (unlikely(error))
+                       break;
+               error = get_user(len, &iov->iov_len);
+               if (unlikely(error))
+                       break;
+
+               /*
+                * Sanity check this iovec. 0 read succeeds.
+                */
+               if (unlikely(!len))
+                       break;
+               if (unlikely(!base)) {
+                       error = -EFAULT;
+                       break;
+               }
+
+               if (unlikely(!access_ok(VERIFY_WRITE, base, len))) {
+                       error = -EFAULT;
+                       break;
+               }
+
+               sd.len = 0;
+               sd.total_len = len;
+               sd.flags = flags;
+               sd.u.userptr = base;
+               sd.pos = 0;
+
+               size = __splice_from_pipe(pipe, &sd, pipe_to_user);
+               if (size < 0) {
+                       if (!ret)
+                               ret = size;
+
+                       break;
+               }
+
+               ret += size;
+
+               if (size < len)
+                       break;
+
+               nr_segs--;
+               iov++;
+       }
+
+       if (pipe->inode)
+               mutex_unlock(&pipe->inode->i_mutex);
+
+       if (!ret)
+               ret = error;
+
+       return ret;
+}
+
+/*
+ * vmsplice splices a user address range into a pipe. It can be thought of
+ * as splice-from-memory, where the regular splice is splice-from-file (or
+ * to file). In both cases the output is a pipe, naturally.
+ */
+static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
+                            unsigned long nr_segs, unsigned int flags)
+{
+       struct pipe_inode_info *pipe;
+       struct page *pages[PIPE_BUFFERS];
+       struct partial_page partial[PIPE_BUFFERS];
+       struct splice_pipe_desc spd = {
+               .pages = pages,
+               .partial = partial,
+               .flags = flags,
+               .ops = &user_page_pipe_buf_ops,
+               .spd_release = spd_release_page,
+       };
+
+       pipe = pipe_info(file->f_path.dentry->d_inode);
+       if (!pipe)
+               return -EBADF;
+
+       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;
+
+       return splice_to_pipe(pipe, &spd);
+}
+
+/*
+ * Note that vmsplice only really supports true splicing _from_ user memory
+ * to a pipe, not the other way around. Splicing from user memory is a simple
+ * operation that can be supported without any funky alignment restrictions
+ * or nasty vm tricks. We simply map in the user memory and fill them into
+ * a pipe. The reverse isn't quite as easy, though. There are two possible
+ * solutions for that:
+ *
+ *     - memcpy() the data internally, at which point we might as well just
+ *       do a regular read() on the buffer anyway.
+ *     - Lots of nasty vm tricks, that are neither fast nor flexible (it
+ *       has restriction limitations on both ends of the pipe).
+ *
+ * Currently we punt and implement it as a normal copy, see pipe_to_user().
+ *
+ */
+SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, iov,
+               unsigned long, nr_segs, unsigned int, flags)
+{
+       struct file *file;
+       long error;
+       int fput;
+
+       if (unlikely(nr_segs > UIO_MAXIOV))
+               return -EINVAL;
+       else if (unlikely(!nr_segs))
+               return 0;
+
+       error = -EBADF;
+       file = fget_light(fd, &fput);
+       if (file) {
+               if (file->f_mode & FMODE_WRITE)
+                       error = vmsplice_to_pipe(file, iov, nr_segs, flags);
+               else if (file->f_mode & FMODE_READ)
+                       error = vmsplice_to_user(file, iov, nr_segs, flags);
+
+               fput_light(file, fput);
+       }
+
+       return error;
+}
+
+SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
+               int, fd_out, loff_t __user *, off_out,
+               size_t, len, unsigned int, flags)
 {
        long error;
        struct file *in, *out;
@@ -961,3 +1491,223 @@ asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
 
        return error;
 }
+
+/*
+ * Make sure there's data to read. Wait for input if we can, otherwise
+ * return an appropriate error.
+ */
+static int link_ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
+{
+       int ret;
+
+       /*
+        * Check ->nrbufs without the inode lock first. This function
+        * is speculative anyways, so missing one is ok.
+        */
+       if (pipe->nrbufs)
+               return 0;
+
+       ret = 0;
+       mutex_lock(&pipe->inode->i_mutex);
+
+       while (!pipe->nrbufs) {
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               if (!pipe->writers)
+                       break;
+               if (!pipe->waiting_writers) {
+                       if (flags & SPLICE_F_NONBLOCK) {
+                               ret = -EAGAIN;
+                               break;
+                       }
+               }
+               pipe_wait(pipe);
+       }
+
+       mutex_unlock(&pipe->inode->i_mutex);
+       return ret;
+}
+
+/*
+ * Make sure there's writeable room. Wait for room if we can, otherwise
+ * return an appropriate error.
+ */
+static int link_opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
+{
+       int ret;
+
+       /*
+        * Check ->nrbufs without the inode lock first. This function
+        * is speculative anyways, so missing one is ok.
+        */
+       if (pipe->nrbufs < PIPE_BUFFERS)
+               return 0;
+
+       ret = 0;
+       mutex_lock(&pipe->inode->i_mutex);
+
+       while (pipe->nrbufs >= PIPE_BUFFERS) {
+               if (!pipe->readers) {
+                       send_sig(SIGPIPE, current, 0);
+                       ret = -EPIPE;
+                       break;
+               }
+               if (flags & SPLICE_F_NONBLOCK) {
+                       ret = -EAGAIN;
+                       break;
+               }
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               pipe->waiting_writers++;
+               pipe_wait(pipe);
+               pipe->waiting_writers--;
+       }
+
+       mutex_unlock(&pipe->inode->i_mutex);
+       return ret;
+}
+
+/*
+ * Link contents of ipipe to opipe.
+ */
+static int link_pipe(struct pipe_inode_info *ipipe,
+                    struct pipe_inode_info *opipe,
+                    size_t len, unsigned int flags)
+{
+       struct pipe_buffer *ibuf, *obuf;
+       int ret = 0, i = 0, nbuf;
+
+       /*
+        * Potential ABBA deadlock, work around it by ordering lock
+        * grabbing by inode address. Otherwise two different processes
+        * could deadlock (one doing tee from A -> B, the other from B -> A).
+        */
+       inode_double_lock(ipipe->inode, opipe->inode);
+
+       do {
+               if (!opipe->readers) {
+                       send_sig(SIGPIPE, current, 0);
+                       if (!ret)
+                               ret = -EPIPE;
+                       break;
+               }
+
+               /*
+                * If we have iterated all input buffers or ran out of
+                * output room, break.
+                */
+               if (i >= ipipe->nrbufs || opipe->nrbufs >= PIPE_BUFFERS)
+                       break;
+
+               ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1));
+               nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1);
+
+               /*
+                * Get a reference to this pipe buffer,
+                * so we can copy the contents over.
+                */
+               ibuf->ops->get(ipipe, ibuf);
+
+               obuf = opipe->bufs + nbuf;
+               *obuf = *ibuf;
+
+               /*
+                * Don't inherit the gift flag, we need to
+                * prevent multiple steals of this page.
+                */
+               obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
+
+               if (obuf->len > len)
+                       obuf->len = len;
+
+               opipe->nrbufs++;
+               ret += obuf->len;
+               len -= obuf->len;
+               i++;
+       } while (len);
+
+       /*
+        * return EAGAIN if we have the potential of some data in the
+        * future, otherwise just return 0
+        */
+       if (!ret && ipipe->waiting_writers && (flags & SPLICE_F_NONBLOCK))
+               ret = -EAGAIN;
+
+       inode_double_unlock(ipipe->inode, opipe->inode);
+
+       /*
+        * If we put data in the output pipe, wakeup any potential readers.
+        */
+       if (ret > 0) {
+               smp_mb();
+               if (waitqueue_active(&opipe->wait))
+                       wake_up_interruptible(&opipe->wait);
+               kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
+       }
+
+       return ret;
+}
+
+/*
+ * This is a tee(1) implementation that works on pipes. It doesn't copy
+ * any data, it simply references the 'in' pages on the 'out' pipe.
+ * The 'flags' used are the SPLICE_F_* variants, currently the only
+ * applicable one is SPLICE_F_NONBLOCK.
+ */
+static long do_tee(struct file *in, struct file *out, size_t len,
+                  unsigned int flags)
+{
+       struct pipe_inode_info *ipipe = pipe_info(in->f_path.dentry->d_inode);
+       struct pipe_inode_info *opipe = pipe_info(out->f_path.dentry->d_inode);
+       int ret = -EINVAL;
+
+       /*
+        * Duplicate the contents of ipipe to opipe without actually
+        * copying the data.
+        */
+       if (ipipe && opipe && ipipe != opipe) {
+               /*
+                * Keep going, unless we encounter an error. The ipipe/opipe
+                * ordering doesn't really matter.
+                */
+               ret = link_ipipe_prep(ipipe, flags);
+               if (!ret) {
+                       ret = link_opipe_prep(opipe, flags);
+                       if (!ret)
+                               ret = link_pipe(ipipe, opipe, len, flags);
+               }
+       }
+
+       return ret;
+}
+
+SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags)
+{
+       struct file *in;
+       int error, fput_in;
+
+       if (unlikely(!len))
+               return 0;
+
+       error = -EBADF;
+       in = fget_light(fdin, &fput_in);
+       if (in) {
+               if (in->f_mode & FMODE_READ) {
+                       int fput_out;
+                       struct file *out = fget_light(fdout, &fput_out);
+
+                       if (out) {
+                               if (out->f_mode & FMODE_WRITE)
+                                       error = do_tee(in, out, len, flags);
+                               fput_light(out, fput_out);
+                       }
+               }
+               fput_light(in, fput_in);
+       }
+
+       return error;
+}