Merge tag 'net-next-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev...
[platform/kernel/linux-starfive.git] / fs / splice.c
index 17d6924..004eb1c 100644 (file)
@@ -300,20 +300,36 @@ void splice_shrink_spd(struct splice_pipe_desc *spd)
        kfree(spd->partial);
 }
 
-/*
- * Splice data from an O_DIRECT file into pages and then add them to the output
- * pipe.
+/**
+ * copy_splice_read -  Copy data from a file and splice the copy into a pipe
+ * @in: The file to read from
+ * @ppos: Pointer to the file position to read from
+ * @pipe: The pipe to splice into
+ * @len: The amount to splice
+ * @flags: The SPLICE_F_* flags
+ *
+ * This function allocates a bunch of pages sufficient to hold the requested
+ * amount of data (but limited by the remaining pipe capacity), passes it to
+ * the file's ->read_iter() to read into and then splices the used pages into
+ * the pipe.
+ *
+ * Return: On success, the number of bytes read will be returned and *@ppos
+ * will be updated if appropriate; 0 will be returned if there is no more data
+ * to be read; -EAGAIN will be returned if the pipe had no space, and some
+ * other negative error code will be returned on error.  A short read may occur
+ * if the pipe has insufficient space, we reach the end of the data or we hit a
+ * hole.
  */
-ssize_t direct_splice_read(struct file *in, loff_t *ppos,
-                          struct pipe_inode_info *pipe,
-                          size_t len, unsigned int flags)
+ssize_t copy_splice_read(struct file *in, loff_t *ppos,
+                        struct pipe_inode_info *pipe,
+                        size_t len, unsigned int flags)
 {
        struct iov_iter to;
        struct bio_vec *bv;
        struct kiocb kiocb;
        struct page **pages;
        ssize_t ret;
-       size_t used, npages, chunk, remain, reclaim;
+       size_t used, npages, chunk, remain, keep = 0;
        int i;
 
        /* Work out how much data we can actually add into the pipe */
@@ -327,7 +343,7 @@ ssize_t direct_splice_read(struct file *in, loff_t *ppos,
        if (!bv)
                return -ENOMEM;
 
-       pages = (void *)(bv + npages);
+       pages = (struct page **)(bv + npages);
        npages = alloc_pages_bulk_array(GFP_USER, npages, pages);
        if (!npages) {
                kfree(bv);
@@ -350,31 +366,25 @@ ssize_t direct_splice_read(struct file *in, loff_t *ppos,
        kiocb.ki_pos = *ppos;
        ret = call_read_iter(in, &kiocb, &to);
 
-       reclaim = npages * PAGE_SIZE;
-       remain = 0;
        if (ret > 0) {
-               reclaim -= ret;
-               remain = ret;
+               keep = DIV_ROUND_UP(ret, PAGE_SIZE);
                *ppos = kiocb.ki_pos;
-               file_accessed(in);
-       } else if (ret < 0) {
-               /*
-                * callers of ->splice_read() expect -EAGAIN on
-                * "can't put anything in there", rather than -EFAULT.
-                */
-               if (ret == -EFAULT)
-                       ret = -EAGAIN;
        }
 
+       /*
+        * Callers of ->splice_read() expect -EAGAIN on "can't put anything in
+        * there", rather than -EFAULT.
+        */
+       if (ret == -EFAULT)
+               ret = -EAGAIN;
+
        /* Free any pages that didn't get touched at all. */
-       reclaim /= PAGE_SIZE;
-       if (reclaim) {
-               npages -= reclaim;
-               release_pages(pages + npages, reclaim);
-       }
+       if (keep < npages)
+               release_pages(pages + keep, npages - keep);
 
        /* Push the remaining pages into the pipe. */
-       for (i = 0; i < npages; i++) {
+       remain = ret;
+       for (i = 0; i < keep; i++) {
                struct pipe_buffer *buf = pipe_head_buf(pipe);
 
                chunk = min_t(size_t, remain, PAGE_SIZE);
@@ -391,50 +401,7 @@ ssize_t direct_splice_read(struct file *in, loff_t *ppos,
        kfree(bv);
        return ret;
 }
-EXPORT_SYMBOL(direct_splice_read);
-
-/**
- * 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
- *
- * Description:
- *    Will read pages from given file and fill them into a pipe. Can be
- *    used as long as it has more or less sane ->read_iter().
- *
- */
-ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
-                                struct pipe_inode_info *pipe, size_t len,
-                                unsigned int flags)
-{
-       struct iov_iter to;
-       struct kiocb kiocb;
-       int ret;
-
-       iov_iter_pipe(&to, ITER_DEST, pipe, len);
-       init_sync_kiocb(&kiocb, in);
-       kiocb.ki_pos = *ppos;
-       ret = call_read_iter(in, &kiocb, &to);
-       if (ret > 0) {
-               *ppos = kiocb.ki_pos;
-               file_accessed(in);
-       } else if (ret < 0) {
-               /* free what was emitted */
-               pipe_discard_from(pipe, to.start_head);
-               /*
-                * callers of ->splice_read() expect -EAGAIN on
-                * "can't put anything in there", rather than -EFAULT.
-                */
-               if (ret == -EFAULT)
-                       ret = -EAGAIN;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(generic_file_splice_read);
+EXPORT_SYMBOL(copy_splice_read);
 
 const struct pipe_buf_operations default_pipe_buf_ops = {
        .release        = generic_pipe_buf_release,
@@ -978,18 +945,32 @@ static void do_splice_eof(struct splice_desc *sd)
                sd->splice_eof(sd);
 }
 
-/*
- * Attempt to initiate a splice from a file to a pipe.
+/**
+ * vfs_splice_read - Read data from a file and splice it into a pipe
+ * @in:                File to splice from
+ * @ppos:      Input file offset
+ * @pipe:      Pipe to splice to
+ * @len:       Number of bytes to splice
+ * @flags:     Splice modifier flags (SPLICE_F_*)
+ *
+ * Splice the requested amount of data from the input file to the pipe.  This
+ * is synchronous as the caller must hold the pipe lock across the entire
+ * operation.
+ *
+ * If successful, it returns the amount of data spliced, 0 if it hit the EOF or
+ * a hole and a negative error code otherwise.
  */
-static long do_splice_to(struct file *in, loff_t *ppos,
-                        struct pipe_inode_info *pipe, size_t len,
-                        unsigned int flags)
+long vfs_splice_read(struct file *in, loff_t *ppos,
+                    struct pipe_inode_info *pipe, size_t len,
+                    unsigned int flags)
 {
        unsigned int p_space;
        int ret;
 
        if (unlikely(!(in->f_mode & FMODE_READ)))
                return -EBADF;
+       if (!len)
+               return 0;
 
        /* Don't try to read more the pipe has space for. */
        p_space = pipe->max_usage - pipe_occupancy(pipe->head, pipe->tail);
@@ -1004,8 +985,15 @@ static long do_splice_to(struct file *in, loff_t *ppos,
 
        if (unlikely(!in->f_op->splice_read))
                return warn_unsupported(in, "read");
+       /*
+        * O_DIRECT and DAX don't deal with the pagecache, so we allocate a
+        * buffer, copy into it and splice that into the pipe.
+        */
+       if ((in->f_flags & O_DIRECT) || IS_DAX(in->f_mapping->host))
+               return copy_splice_read(in, ppos, pipe, len, flags);
        return in->f_op->splice_read(in, ppos, pipe, len, flags);
 }
+EXPORT_SYMBOL_GPL(vfs_splice_read);
 
 /**
  * splice_direct_to_actor - splices data directly between two non-pipes
@@ -1079,7 +1067,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
                size_t read_len;
                loff_t pos = sd->pos, prev_pos = pos;
 
-               ret = do_splice_to(in, &pos, pipe, len, flags);
+               ret = vfs_splice_read(in, &pos, pipe, len, flags);
                if (unlikely(ret <= 0))
                        goto read_failure;
 
@@ -1243,7 +1231,7 @@ long splice_file_to_pipe(struct file *in,
        pipe_lock(opipe);
        ret = wait_for_space(opipe, flags);
        if (!ret)
-               ret = do_splice_to(in, offset, opipe, len, flags);
+               ret = vfs_splice_read(in, offset, opipe, len, flags);
        pipe_unlock(opipe);
        if (ret > 0)
                wakeup_pipe_readers(opipe);