io_uring: split out splice related operations
authorJens Axboe <axboe@kernel.dk>
Wed, 25 May 2022 03:19:47 +0000 (21:19 -0600)
committerJens Axboe <axboe@kernel.dk>
Mon, 25 Jul 2022 00:39:11 +0000 (18:39 -0600)
This splits out splice and tee support.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_uring/Makefile
io_uring/io_uring.c
io_uring/io_uring.h
io_uring/splice.c [new file with mode: 0644]
io_uring/splice.h [new file with mode: 0644]

index 50e68c9..c6aca2a 100644 (file)
@@ -2,5 +2,5 @@
 #
 # Makefile for io_uring
 
-obj-$(CONFIG_IO_URING)         += io_uring.o xattr.o nop.o fs.o
+obj-$(CONFIG_IO_URING)         += io_uring.o xattr.o nop.o fs.o splice.o
 obj-$(CONFIG_IO_WQ)            += io-wq.o
index 5b1e67f..43d4044 100644 (file)
@@ -95,6 +95,7 @@
 #include "xattr.h"
 #include "nop.h"
 #include "fs.h"
+#include "splice.h"
 
 #define IORING_MAX_ENTRIES     32768
 #define IORING_MAX_CQ_ENTRIES  (2 * IORING_MAX_ENTRIES)
@@ -436,15 +437,6 @@ struct io_epoll {
        struct epoll_event              event;
 };
 
-struct io_splice {
-       struct file                     *file_out;
-       loff_t                          off_out;
-       loff_t                          off_in;
-       u64                             len;
-       int                             splice_fd_in;
-       unsigned int                    flags;
-};
-
 struct io_provide_buf {
        struct file                     *file;
        __u64                           addr;
@@ -596,9 +588,6 @@ static int __io_register_rsrc_update(struct io_ring_ctx *ctx, unsigned type,
                                     struct io_uring_rsrc_update2 *up,
                                     unsigned nr_args);
 static void io_clean_op(struct io_kiocb *req);
-static inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
-                                            unsigned issue_flags);
-static struct file *io_file_get_normal(struct io_kiocb *req, int fd);
 static void io_queue_sqe(struct io_kiocb *req);
 static void io_rsrc_put_work(struct work_struct *work);
 
@@ -1078,15 +1067,6 @@ static inline bool req_has_async_data(struct io_kiocb *req)
        return req->flags & REQ_F_ASYNC_DATA;
 }
 
-static inline void req_set_fail(struct io_kiocb *req)
-{
-       req->flags |= REQ_F_FAIL;
-       if (req->flags & REQ_F_CQE_SKIP) {
-               req->flags &= ~REQ_F_CQE_SKIP;
-               req->flags |= REQ_F_SKIP_LINK_CQES;
-       }
-}
-
 static inline void req_fail_link_node(struct io_kiocb *req, int res)
 {
        req_set_fail(req);
@@ -1941,12 +1921,6 @@ static inline struct io_kiocb *io_alloc_req(struct io_ring_ctx *ctx)
        return container_of(node, struct io_kiocb, comp_list);
 }
 
-static inline void io_put_file(struct file *file)
-{
-       if (file)
-               fput(file);
-}
-
 static inline void io_dismantle_req(struct io_kiocb *req)
 {
        unsigned int flags = req->flags;
@@ -3919,105 +3893,6 @@ static int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
        return IOU_ISSUE_SKIP_COMPLETE;
 }
 
-static int __io_splice_prep(struct io_kiocb *req,
-                           const struct io_uring_sqe *sqe)
-{
-       struct io_splice *sp = io_kiocb_to_cmd(req);
-       unsigned int valid_flags = SPLICE_F_FD_IN_FIXED | SPLICE_F_ALL;
-
-       sp->len = READ_ONCE(sqe->len);
-       sp->flags = READ_ONCE(sqe->splice_flags);
-       if (unlikely(sp->flags & ~valid_flags))
-               return -EINVAL;
-       sp->splice_fd_in = READ_ONCE(sqe->splice_fd_in);
-       return 0;
-}
-
-static int io_tee_prep(struct io_kiocb *req,
-                      const struct io_uring_sqe *sqe)
-{
-       if (READ_ONCE(sqe->splice_off_in) || READ_ONCE(sqe->off))
-               return -EINVAL;
-       return __io_splice_prep(req, sqe);
-}
-
-static int io_tee(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_splice *sp = io_kiocb_to_cmd(req);
-       struct file *out = sp->file_out;
-       unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
-       struct file *in;
-       long ret = 0;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       if (sp->flags & SPLICE_F_FD_IN_FIXED)
-               in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
-       else
-               in = io_file_get_normal(req, sp->splice_fd_in);
-       if (!in) {
-               ret = -EBADF;
-               goto done;
-       }
-
-       if (sp->len)
-               ret = do_tee(in, out, sp->len, flags);
-
-       if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
-               io_put_file(in);
-done:
-       if (ret != sp->len)
-               req_set_fail(req);
-       io_req_set_res(req, ret, 0);
-       return IOU_OK;
-}
-
-static int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
-{
-       struct io_splice *sp = io_kiocb_to_cmd(req);
-
-       sp->off_in = READ_ONCE(sqe->splice_off_in);
-       sp->off_out = READ_ONCE(sqe->off);
-       return __io_splice_prep(req, sqe);
-}
-
-static int io_splice(struct io_kiocb *req, unsigned int issue_flags)
-{
-       struct io_splice *sp = io_kiocb_to_cmd(req);
-       struct file *out = sp->file_out;
-       unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
-       loff_t *poff_in, *poff_out;
-       struct file *in;
-       long ret = 0;
-
-       if (issue_flags & IO_URING_F_NONBLOCK)
-               return -EAGAIN;
-
-       if (sp->flags & SPLICE_F_FD_IN_FIXED)
-               in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
-       else
-               in = io_file_get_normal(req, sp->splice_fd_in);
-       if (!in) {
-               ret = -EBADF;
-               goto done;
-       }
-
-       poff_in = (sp->off_in == -1) ? NULL : &sp->off_in;
-       poff_out = (sp->off_out == -1) ? NULL : &sp->off_out;
-
-       if (sp->len)
-               ret = do_splice(in, poff_in, out, poff_out, sp->len, flags);
-
-       if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
-               io_put_file(in);
-done:
-       if (ret != sp->len)
-               req_set_fail(req);
-       io_req_set_res(req, ret, 0);
-       return IOU_OK;
-}
-
 static int io_msg_ring_prep(struct io_kiocb *req,
                            const struct io_uring_sqe *sqe)
 {
@@ -7157,8 +7032,8 @@ static void io_fixed_file_set(struct io_fixed_file *file_slot, struct file *file
        file_slot->file_ptr = file_ptr;
 }
 
-static inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
-                                            unsigned int issue_flags)
+inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
+                                     unsigned int issue_flags)
 {
        struct io_ring_ctx *ctx = req->ctx;
        struct file *file = NULL;
@@ -7181,7 +7056,7 @@ out:
        return file;
 }
 
-static struct file *io_file_get_normal(struct io_kiocb *req, int fd)
+struct file *io_file_get_normal(struct io_kiocb *req, int fd)
 {
        struct file *file = fget(fd);
 
index 73943db..02c0012 100644 (file)
@@ -9,10 +9,29 @@ enum {
        IOU_ISSUE_SKIP_COMPLETE = -EIOCBQUEUED,
 };
 
+static inline void req_set_fail(struct io_kiocb *req)
+{
+       req->flags |= REQ_F_FAIL;
+       if (req->flags & REQ_F_CQE_SKIP) {
+               req->flags &= ~REQ_F_CQE_SKIP;
+               req->flags |= REQ_F_SKIP_LINK_CQES;
+       }
+}
+
 static inline void io_req_set_res(struct io_kiocb *req, s32 res, u32 cflags)
 {
        req->cqe.res = res;
        req->cqe.flags = cflags;
 }
 
+static inline void io_put_file(struct file *file)
+{
+       if (file)
+               fput(file);
+}
+
+struct file *io_file_get_normal(struct io_kiocb *req, int fd);
+struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
+                              unsigned issue_flags);
+
 #endif
diff --git a/io_uring/splice.c b/io_uring/splice.c
new file mode 100644 (file)
index 0000000..0e19d63
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/namei.h>
+#include <linux/io_uring.h>
+#include <linux/splice.h>
+
+#include <uapi/linux/io_uring.h>
+
+#include "io_uring_types.h"
+#include "io_uring.h"
+#include "splice.h"
+
+struct io_splice {
+       struct file                     *file_out;
+       loff_t                          off_out;
+       loff_t                          off_in;
+       u64                             len;
+       int                             splice_fd_in;
+       unsigned int                    flags;
+};
+
+static int __io_splice_prep(struct io_kiocb *req,
+                           const struct io_uring_sqe *sqe)
+{
+       struct io_splice *sp = io_kiocb_to_cmd(req);
+       unsigned int valid_flags = SPLICE_F_FD_IN_FIXED | SPLICE_F_ALL;
+
+       sp->len = READ_ONCE(sqe->len);
+       sp->flags = READ_ONCE(sqe->splice_flags);
+       if (unlikely(sp->flags & ~valid_flags))
+               return -EINVAL;
+       sp->splice_fd_in = READ_ONCE(sqe->splice_fd_in);
+       return 0;
+}
+
+int io_tee_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       if (READ_ONCE(sqe->splice_off_in) || READ_ONCE(sqe->off))
+               return -EINVAL;
+       return __io_splice_prep(req, sqe);
+}
+
+int io_tee(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_splice *sp = io_kiocb_to_cmd(req);
+       struct file *out = sp->file_out;
+       unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
+       struct file *in;
+       long ret = 0;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       if (sp->flags & SPLICE_F_FD_IN_FIXED)
+               in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
+       else
+               in = io_file_get_normal(req, sp->splice_fd_in);
+       if (!in) {
+               ret = -EBADF;
+               goto done;
+       }
+
+       if (sp->len)
+               ret = do_tee(in, out, sp->len, flags);
+
+       if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
+               io_put_file(in);
+done:
+       if (ret != sp->len)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
+
+int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_splice *sp = io_kiocb_to_cmd(req);
+
+       sp->off_in = READ_ONCE(sqe->splice_off_in);
+       sp->off_out = READ_ONCE(sqe->off);
+       return __io_splice_prep(req, sqe);
+}
+
+int io_splice(struct io_kiocb *req, unsigned int issue_flags)
+{
+       struct io_splice *sp = io_kiocb_to_cmd(req);
+       struct file *out = sp->file_out;
+       unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
+       loff_t *poff_in, *poff_out;
+       struct file *in;
+       long ret = 0;
+
+       if (issue_flags & IO_URING_F_NONBLOCK)
+               return -EAGAIN;
+
+       if (sp->flags & SPLICE_F_FD_IN_FIXED)
+               in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
+       else
+               in = io_file_get_normal(req, sp->splice_fd_in);
+       if (!in) {
+               ret = -EBADF;
+               goto done;
+       }
+
+       poff_in = (sp->off_in == -1) ? NULL : &sp->off_in;
+       poff_out = (sp->off_out == -1) ? NULL : &sp->off_out;
+
+       if (sp->len)
+               ret = do_splice(in, poff_in, out, poff_out, sp->len, flags);
+
+       if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
+               io_put_file(in);
+done:
+       if (ret != sp->len)
+               req_set_fail(req);
+       io_req_set_res(req, ret, 0);
+       return IOU_OK;
+}
diff --git a/io_uring/splice.h b/io_uring/splice.h
new file mode 100644 (file)
index 0000000..542f941
--- /dev/null
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+int io_tee_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_tee(struct io_kiocb *req, unsigned int issue_flags);
+
+int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+int io_splice(struct io_kiocb *req, unsigned int issue_flags);