fs: fork splice_file_range() from do_splice_direct()
authorAmir Goldstein <amir73il@gmail.com>
Thu, 30 Nov 2023 14:16:22 +0000 (16:16 +0200)
committerChristian Brauner <brauner@kernel.org>
Fri, 1 Dec 2023 10:39:50 +0000 (11:39 +0100)
In preparation of calling do_splice_direct() without file_start_write()
held, create a new helper splice_file_range(), to be called from context
of ->copy_file_range() methods instead of do_splice_direct().

Currently, the only difference is that splice_file_range() does not take
flags argument and that it asserts that file_start_write() is held, but
we factor out a common helper do_splice_direct_actor() that will be used
later.

Use the new helper from __ceph_copy_file_range(), that was incorrectly
passing to do_splice_direct() the copy flags argument as splice flags.
The value of copy flags in ceph is always 0, so it is a smenatic bug fix.

Move the declaration of both helpers to linux/splice.h.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Link: https://lore.kernel.org/r/20231130141624.3338942-2-amir73il@gmail.com
Acked-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/ceph/file.c
fs/read_write.c
fs/splice.c
include/linux/fs.h
include/linux/splice.h

index 3b5aae2..f11de6e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/falloc.h>
 #include <linux/iversion.h>
 #include <linux/ktime.h>
+#include <linux/splice.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -3010,8 +3011,8 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
                 * {read,write}_iter, which will get caps again.
                 */
                put_rd_wr_caps(src_ci, src_got, dst_ci, dst_got);
-               ret = do_splice_direct(src_file, &src_off, dst_file,
-                                      &dst_off, src_objlen, flags);
+               ret = splice_file_range(src_file, &src_off, dst_file, &dst_off,
+                                       src_objlen);
                /* Abort on short copies or on error */
                if (ret < (long)src_objlen) {
                        doutc(cl, "Failed partial copy (%zd)\n", ret);
@@ -3065,8 +3066,8 @@ out_caps:
         */
        if (len && (len < src_ci->i_layout.object_size)) {
                doutc(cl, "Final partial copy of %zu bytes\n", len);
-               bytes = do_splice_direct(src_file, &src_off, dst_file,
-                                        &dst_off, len, flags);
+               bytes = splice_file_range(src_file, &src_off, dst_file,
+                                         &dst_off, len);
                if (bytes > 0)
                        ret += bytes;
                else
index f791555..642c7ce 100644 (file)
@@ -1423,10 +1423,8 @@ ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
                                struct file *file_out, loff_t pos_out,
                                size_t len, unsigned int flags)
 {
-       lockdep_assert(file_write_started(file_out));
-
-       return do_splice_direct(file_in, &pos_in, file_out, &pos_out,
-                               len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
+       return splice_file_range(file_in, &pos_in, file_out, &pos_out,
+                                min_t(size_t, len, MAX_RW_COUNT));
 }
 EXPORT_SYMBOL(generic_copy_file_range);
 
index 3fce5f6..9007b2c 100644 (file)
@@ -1170,25 +1170,10 @@ static void direct_file_splice_eof(struct splice_desc *sd)
                file->f_op->splice_eof(file);
 }
 
-/**
- * do_splice_direct - splices data directly between two files
- * @in:                file to splice from
- * @ppos:      input file offset
- * @out:       file to splice to
- * @opos:      output file offset
- * @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.
- *
- * Callers already called rw_verify_area() on the entire range.
- */
-long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
-                     loff_t *opos, size_t len, unsigned int flags)
+static long do_splice_direct_actor(struct file *in, loff_t *ppos,
+                                  struct file *out, loff_t *opos,
+                                  size_t len, unsigned int flags,
+                                  splice_direct_actor *actor)
 {
        struct splice_desc sd = {
                .len            = len,
@@ -1207,14 +1192,60 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
        if (unlikely(out->f_flags & O_APPEND))
                return -EINVAL;
 
-       ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
+       ret = splice_direct_to_actor(in, &sd, actor);
        if (ret > 0)
                *ppos = sd.pos;
 
        return ret;
 }
+/**
+ * do_splice_direct - splices data directly between two files
+ * @in:                file to splice from
+ * @ppos:      input file offset
+ * @out:       file to splice to
+ * @opos:      output file offset
+ * @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.
+ *
+ * Callers already called rw_verify_area() on the entire range.
+ */
+long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
+                     loff_t *opos, size_t len, unsigned int flags)
+{
+       return do_splice_direct_actor(in, ppos, out, opos, len, flags,
+                                     direct_splice_actor);
+}
 EXPORT_SYMBOL(do_splice_direct);
 
+/**
+ * splice_file_range - splices data between two files for copy_file_range()
+ * @in:                file to splice from
+ * @ppos:      input file offset
+ * @out:       file to splice to
+ * @opos:      output file offset
+ * @len:       number of bytes to splice
+ *
+ * Description:
+ *    For use by generic_copy_file_range() and ->copy_file_range() methods.
+ *
+ * Callers already called rw_verify_area() on the entire range.
+ */
+long splice_file_range(struct file *in, loff_t *ppos, struct file *out,
+                      loff_t *opos, size_t len)
+{
+       lockdep_assert(file_write_started(out));
+
+       return do_splice_direct_actor(in, ppos, out, opos, len, 0,
+                                     direct_splice_actor);
+}
+EXPORT_SYMBOL(splice_file_range);
+
 static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
 {
        for (;;) {
index ae0e2fb..04422a0 100644 (file)
@@ -3052,8 +3052,6 @@ ssize_t copy_splice_read(struct file *in, loff_t *ppos,
                         size_t len, unsigned int flags);
 extern ssize_t iter_file_splice_write(struct pipe_inode_info *,
                struct file *, loff_t *, size_t, unsigned int);
-extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
-               loff_t *opos, size_t len, unsigned int flags);
 
 
 extern void
index 6c46157..49532d5 100644 (file)
@@ -80,11 +80,14 @@ extern ssize_t add_to_pipe(struct pipe_inode_info *,
 long vfs_splice_read(struct file *in, loff_t *ppos,
                     struct pipe_inode_info *pipe, size_t len,
                     unsigned int flags);
-extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
-                                     splice_direct_actor *);
-extern long do_splice(struct file *in, loff_t *off_in,
-                     struct file *out, loff_t *off_out,
-                     size_t len, unsigned int flags);
+ssize_t splice_direct_to_actor(struct file *file, struct splice_desc *sd,
+                              splice_direct_actor *actor);
+long do_splice(struct file *in, loff_t *off_in, struct file *out,
+              loff_t *off_out, size_t len, unsigned int flags);
+long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
+                     loff_t *opos, size_t len, unsigned int flags);
+long splice_file_range(struct file *in, loff_t *ppos, struct file *out,
+                      loff_t *opos, size_t len);
 
 extern long do_tee(struct file *in, struct file *out, size_t len,
                   unsigned int flags);