Merge branch 'work.set_fs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / fs / splice.c
index 412df7b..599b740 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/security.h>
 #include <linux/gfp.h>
 #include <linux/socket.h>
-#include <linux/compat.h>
 #include <linux/sched/signal.h>
 
 #include "internal.h"
@@ -443,6 +442,22 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
        return 1;
 }
 
+/* We know we have a pipe buffer, but maybe it's empty? */
+static inline bool eat_empty_buffer(struct pipe_inode_info *pipe)
+{
+       unsigned int tail = pipe->tail;
+       unsigned int mask = pipe->ring_size - 1;
+       struct pipe_buffer *buf = &pipe->bufs[tail & mask];
+
+       if (unlikely(!buf->len)) {
+               pipe_buf_release(pipe, buf);
+               pipe->tail = tail+1;
+               return true;
+       }
+
+       return false;
+}
+
 /**
  * splice_from_pipe_next - wait for some data to splice from
  * @pipe:      pipe to splice from
@@ -462,6 +477,7 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des
        if (signal_pending(current))
                return -ERESTARTSYS;
 
+repeat:
        while (pipe_empty(pipe->head, pipe->tail)) {
                if (!pipe->writers)
                        return 0;
@@ -480,9 +496,12 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des
                        sd->need_wakeup = false;
                }
 
-               pipe_wait(pipe);
+               pipe_wait_readable(pipe);
        }
 
+       if (eat_empty_buffer(pipe))
+               goto repeat;
+
        return 1;
 }
 
@@ -975,7 +994,7 @@ static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
                        return -EAGAIN;
                if (signal_pending(current))
                        return -ERESTARTSYS;
-               pipe_wait(pipe);
+               pipe_wait_writable(pipe);
        }
 }
 
@@ -1230,20 +1249,6 @@ static int vmsplice_type(struct fd f, int *type)
  * Currently we punt and implement it as a normal copy, see pipe_to_user().
  *
  */
-static long do_vmsplice(struct file *f, struct iov_iter *iter, unsigned int flags)
-{
-       if (unlikely(flags & ~SPLICE_F_ALL))
-               return -EINVAL;
-
-       if (!iov_iter_count(iter))
-               return 0;
-
-       if (iov_iter_rw(iter) == WRITE)
-               return vmsplice_to_pipe(f, iter, flags);
-       else
-               return vmsplice_to_user(f, iter, flags);
-}
-
 SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
                unsigned long, nr_segs, unsigned int, flags)
 {
@@ -1254,6 +1259,9 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
        struct fd f;
        int type;
 
+       if (unlikely(flags & ~SPLICE_F_ALL))
+               return -EINVAL;
+
        f = fdget(fd);
        error = vmsplice_type(f, &type);
        if (error)
@@ -1261,40 +1269,21 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
 
        error = import_iovec(type, uiov, nr_segs,
                             ARRAY_SIZE(iovstack), &iov, &iter);
-       if (error >= 0) {
-               error = do_vmsplice(f.file, &iter, flags);
-               kfree(iov);
-       }
-       fdput(f);
-       return error;
-}
-
-#ifdef CONFIG_COMPAT
-COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, iov32,
-                   unsigned int, nr_segs, unsigned int, flags)
-{
-       struct iovec iovstack[UIO_FASTIOV];
-       struct iovec *iov = iovstack;
-       struct iov_iter iter;
-       ssize_t error;
-       struct fd f;
-       int type;
+       if (error < 0)
+               goto out_fdput;
 
-       f = fdget(fd);
-       error = vmsplice_type(f, &type);
-       if (error)
-               return error;
+       if (!iov_iter_count(&iter))
+               error = 0;
+       else if (iov_iter_rw(&iter) == WRITE)
+               error = vmsplice_to_pipe(f.file, &iter, flags);
+       else
+               error = vmsplice_to_user(f.file, &iter, flags);
 
-       error = compat_import_iovec(type, iov32, nr_segs,
-                            ARRAY_SIZE(iovstack), &iov, &iter);
-       if (error >= 0) {
-               error = do_vmsplice(f.file, &iter, flags);
-               kfree(iov);
-       }
+       kfree(iov);
+out_fdput:
        fdput(f);
        return error;
 }
-#endif
 
 SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
                int, fd_out, loff_t __user *, off_out,
@@ -1352,7 +1341,7 @@ static int ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
                        ret = -EAGAIN;
                        break;
                }
-               pipe_wait(pipe);
+               pipe_wait_readable(pipe);
        }
 
        pipe_unlock(pipe);
@@ -1391,7 +1380,7 @@ static int opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
                        ret = -ERESTARTSYS;
                        break;
                }
-               pipe_wait(pipe);
+               pipe_wait_writable(pipe);
        }
 
        pipe_unlock(pipe);