1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/kernel.h>
3 #include <linux/errno.h>
5 #include <linux/file.h>
7 #include <linux/slab.h>
8 #include <linux/namei.h>
9 #include <linux/io_uring.h>
10 #include <linux/splice.h>
12 #include <uapi/linux/io_uring.h>
18 struct file
*file_out
;
26 static int __io_splice_prep(struct io_kiocb
*req
,
27 const struct io_uring_sqe
*sqe
)
29 struct io_splice
*sp
= io_kiocb_to_cmd(req
, struct io_splice
);
30 unsigned int valid_flags
= SPLICE_F_FD_IN_FIXED
| SPLICE_F_ALL
;
32 sp
->len
= READ_ONCE(sqe
->len
);
33 sp
->flags
= READ_ONCE(sqe
->splice_flags
);
34 if (unlikely(sp
->flags
& ~valid_flags
))
36 sp
->splice_fd_in
= READ_ONCE(sqe
->splice_fd_in
);
37 req
->flags
|= REQ_F_FORCE_ASYNC
;
41 int io_tee_prep(struct io_kiocb
*req
, const struct io_uring_sqe
*sqe
)
43 if (READ_ONCE(sqe
->splice_off_in
) || READ_ONCE(sqe
->off
))
45 return __io_splice_prep(req
, sqe
);
48 int io_tee(struct io_kiocb
*req
, unsigned int issue_flags
)
50 struct io_splice
*sp
= io_kiocb_to_cmd(req
, struct io_splice
);
51 struct file
*out
= sp
->file_out
;
52 unsigned int flags
= sp
->flags
& ~SPLICE_F_FD_IN_FIXED
;
56 WARN_ON_ONCE(issue_flags
& IO_URING_F_NONBLOCK
);
58 if (sp
->flags
& SPLICE_F_FD_IN_FIXED
)
59 in
= io_file_get_fixed(req
, sp
->splice_fd_in
, issue_flags
);
61 in
= io_file_get_normal(req
, sp
->splice_fd_in
);
68 ret
= do_tee(in
, out
, sp
->len
, flags
);
70 if (!(sp
->flags
& SPLICE_F_FD_IN_FIXED
))
75 io_req_set_res(req
, ret
, 0);
79 int io_splice_prep(struct io_kiocb
*req
, const struct io_uring_sqe
*sqe
)
81 struct io_splice
*sp
= io_kiocb_to_cmd(req
, struct io_splice
);
83 sp
->off_in
= READ_ONCE(sqe
->splice_off_in
);
84 sp
->off_out
= READ_ONCE(sqe
->off
);
85 return __io_splice_prep(req
, sqe
);
88 int io_splice(struct io_kiocb
*req
, unsigned int issue_flags
)
90 struct io_splice
*sp
= io_kiocb_to_cmd(req
, struct io_splice
);
91 struct file
*out
= sp
->file_out
;
92 unsigned int flags
= sp
->flags
& ~SPLICE_F_FD_IN_FIXED
;
93 loff_t
*poff_in
, *poff_out
;
97 WARN_ON_ONCE(issue_flags
& IO_URING_F_NONBLOCK
);
99 if (sp
->flags
& SPLICE_F_FD_IN_FIXED
)
100 in
= io_file_get_fixed(req
, sp
->splice_fd_in
, issue_flags
);
102 in
= io_file_get_normal(req
, sp
->splice_fd_in
);
108 poff_in
= (sp
->off_in
== -1) ? NULL
: &sp
->off_in
;
109 poff_out
= (sp
->off_out
== -1) ? NULL
: &sp
->off_out
;
112 ret
= do_splice(in
, poff_in
, out
, poff_out
, sp
->len
, flags
);
114 if (!(sp
->flags
& SPLICE_F_FD_IN_FIXED
))
119 io_req_set_res(req
, ret
, 0);