0001
0002 #include <linux/kernel.h>
0003 #include <linux/errno.h>
0004 #include <linux/fs.h>
0005 #include <linux/file.h>
0006 #include <linux/mm.h>
0007 #include <linux/slab.h>
0008 #include <linux/namei.h>
0009 #include <linux/io_uring.h>
0010 #include <linux/splice.h>
0011
0012 #include <uapi/linux/io_uring.h>
0013
0014 #include "io_uring.h"
0015 #include "splice.h"
0016
0017 struct io_splice {
0018 struct file *file_out;
0019 loff_t off_out;
0020 loff_t off_in;
0021 u64 len;
0022 int splice_fd_in;
0023 unsigned int flags;
0024 };
0025
0026 static int __io_splice_prep(struct io_kiocb *req,
0027 const struct io_uring_sqe *sqe)
0028 {
0029 struct io_splice *sp = io_kiocb_to_cmd(req, struct io_splice);
0030 unsigned int valid_flags = SPLICE_F_FD_IN_FIXED | SPLICE_F_ALL;
0031
0032 sp->len = READ_ONCE(sqe->len);
0033 sp->flags = READ_ONCE(sqe->splice_flags);
0034 if (unlikely(sp->flags & ~valid_flags))
0035 return -EINVAL;
0036 sp->splice_fd_in = READ_ONCE(sqe->splice_fd_in);
0037 return 0;
0038 }
0039
0040 int io_tee_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
0041 {
0042 if (READ_ONCE(sqe->splice_off_in) || READ_ONCE(sqe->off))
0043 return -EINVAL;
0044 return __io_splice_prep(req, sqe);
0045 }
0046
0047 int io_tee(struct io_kiocb *req, unsigned int issue_flags)
0048 {
0049 struct io_splice *sp = io_kiocb_to_cmd(req, struct io_splice);
0050 struct file *out = sp->file_out;
0051 unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
0052 struct file *in;
0053 long ret = 0;
0054
0055 if (issue_flags & IO_URING_F_NONBLOCK)
0056 return -EAGAIN;
0057
0058 if (sp->flags & SPLICE_F_FD_IN_FIXED)
0059 in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
0060 else
0061 in = io_file_get_normal(req, sp->splice_fd_in);
0062 if (!in) {
0063 ret = -EBADF;
0064 goto done;
0065 }
0066
0067 if (sp->len)
0068 ret = do_tee(in, out, sp->len, flags);
0069
0070 if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
0071 io_put_file(in);
0072 done:
0073 if (ret != sp->len)
0074 req_set_fail(req);
0075 io_req_set_res(req, ret, 0);
0076 return IOU_OK;
0077 }
0078
0079 int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
0080 {
0081 struct io_splice *sp = io_kiocb_to_cmd(req, struct io_splice);
0082
0083 sp->off_in = READ_ONCE(sqe->splice_off_in);
0084 sp->off_out = READ_ONCE(sqe->off);
0085 return __io_splice_prep(req, sqe);
0086 }
0087
0088 int io_splice(struct io_kiocb *req, unsigned int issue_flags)
0089 {
0090 struct io_splice *sp = io_kiocb_to_cmd(req, struct io_splice);
0091 struct file *out = sp->file_out;
0092 unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
0093 loff_t *poff_in, *poff_out;
0094 struct file *in;
0095 long ret = 0;
0096
0097 if (issue_flags & IO_URING_F_NONBLOCK)
0098 return -EAGAIN;
0099
0100 if (sp->flags & SPLICE_F_FD_IN_FIXED)
0101 in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
0102 else
0103 in = io_file_get_normal(req, sp->splice_fd_in);
0104 if (!in) {
0105 ret = -EBADF;
0106 goto done;
0107 }
0108
0109 poff_in = (sp->off_in == -1) ? NULL : &sp->off_in;
0110 poff_out = (sp->off_out == -1) ? NULL : &sp->off_out;
0111
0112 if (sp->len)
0113 ret = do_splice(in, poff_in, out, poff_out, sp->len, flags);
0114
0115 if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
0116 io_put_file(in);
0117 done:
0118 if (ret != sp->len)
0119 req_set_fail(req);
0120 io_req_set_res(req, ret, 0);
0121 return IOU_OK;
0122 }