]> err.no Git - linux-2.6/blobdiff - fs/splice.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6
[linux-2.6] / fs / splice.c
index 684bca3d3a107c021715f8394a1f1d23a1913aaa..8d705954d2946f9a4209107dde5412e651286f12 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>
  *
@@ -74,7 +74,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
                wait_on_page_writeback(page);
 
                if (PagePrivate(page))
-                       try_to_release_page(page, mapping_gfp_mask(mapping));
+                       try_to_release_page(page, GFP_KERNEL);
 
                /*
                 * If we succeeded in removing the mapping, set LRU flag
@@ -333,7 +333,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                                break;
 
                        error = add_to_page_cache_lru(page, mapping, index,
-                                             mapping_gfp_mask(mapping));
+                                             GFP_KERNEL);
                        if (unlikely(error)) {
                                page_cache_release(page);
                                if (error == -EEXIST)
@@ -557,7 +557,6 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
 {
        struct file *file = sd->file;
        struct address_space *mapping = file->f_mapping;
-       gfp_t gfp_mask = mapping_gfp_mask(mapping);
        unsigned int offset, this_len;
        struct page *page;
        pgoff_t index;
@@ -591,7 +590,7 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
                        goto find_page;
 
                page = buf->page;
-               if (add_to_page_cache(page, mapping, index, gfp_mask)) {
+               if (add_to_page_cache(page, mapping, index, GFP_KERNEL)) {
                        unlock_page(page);
                        goto find_page;
                }
@@ -607,13 +606,13 @@ find_page:
                        ret = -ENOMEM;
                        page = page_cache_alloc_cold(mapping);
                        if (unlikely(!page))
-                               goto out_nomem;
+                               goto out_ret;
 
                        /*
                         * This will also lock the page
                         */
                        ret = add_to_page_cache_lru(page, mapping, index,
-                                                   gfp_mask);
+                                                   GFP_KERNEL);
                        if (unlikely(ret))
                                goto out;
                }
@@ -666,7 +665,7 @@ find_page:
                if (sd->pos + this_len > isize)
                        vmtruncate(mapping->host, isize);
 
-               goto out;
+               goto out_ret;
        }
 
        if (buf->page != page) {
@@ -698,7 +697,7 @@ find_page:
 out:
        page_cache_release(page);
        unlock_page(page);
-out_nomem:
+out_ret:
        return ret;
 }
 
@@ -707,9 +706,9 @@ out_nomem:
  * 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.
  */
-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)
+static 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)
 {
        int ret, do_wakeup, err;
        struct splice_desc sd;
@@ -722,9 +721,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
        sd.file = out;
        sd.pos = *ppos;
 
-       if (pipe->inode)
-               mutex_lock(&pipe->inode->i_mutex);
-
        for (;;) {
                if (pipe->nrbufs) {
                        struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
@@ -797,9 +793,6 @@ ssize_t splice_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))
@@ -810,6 +803,73 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
        return ret;
 }
 
+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;
+
+       /*
+        * The actor worker might be calling ->prepare_write and
+        * ->commit_write. 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, out, ppos, len, flags, 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
+ * @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. 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;
+       ssize_t ret;
+       int err;
+
+       err = remove_suid(out->f_dentry);
+       if (unlikely(err))
+               return err;
+
+       ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
+       if (ret > 0) {
+               *ppos += ret;
+
+               /*
+                * 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;
+               }
+       }
+
+       return ret;
+}
+
+EXPORT_SYMBOL(generic_file_splice_write_nolock);
+
 /**
  * generic_file_splice_write - splice data from a pipe to a file
  * @pipe:      pipe info
@@ -826,12 +886,21 @@ generic_file_splice_write(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;
        ssize_t ret;
+       int err;
+
+       err = should_remove_suid(out->f_dentry);
+       if (unlikely(err)) {
+               mutex_lock(&inode->i_mutex);
+               err = __remove_suid(out->f_dentry, err);
+               mutex_unlock(&inode->i_mutex);
+               if (err)
+                       return err;
+       }
 
        ret = splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
        if (ret > 0) {
-               struct inode *inode = mapping->host;
-
                *ppos += ret;
 
                /*
@@ -839,8 +908,6 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
                 * 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);
@@ -1400,13 +1467,7 @@ static int link_pipe(struct pipe_inode_info *ipipe,
         * grabbing by inode address. Otherwise two different processes
         * could deadlock (one doing tee from A -> B, the other from B -> A).
         */
-       if (ipipe->inode < opipe->inode) {
-               mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_PARENT);
-               mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_CHILD);
-       } else {
-               mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_PARENT);
-               mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_CHILD);
-       }
+       inode_double_lock(ipipe->inode, opipe->inode);
 
        do {
                if (!opipe->readers) {
@@ -1450,8 +1511,7 @@ static int link_pipe(struct pipe_inode_info *ipipe,
                i++;
        } while (len);
 
-       mutex_unlock(&ipipe->inode->i_mutex);
-       mutex_unlock(&opipe->inode->i_mutex);
+       inode_double_unlock(ipipe->inode, opipe->inode);
 
        /*
         * If we put data in the output pipe, wakeup any potential readers.