xref: /openbmc/linux/io_uring/splice.c (revision 9f69a259)
1531113bbSJens Axboe // SPDX-License-Identifier: GPL-2.0
2531113bbSJens Axboe #include <linux/kernel.h>
3531113bbSJens Axboe #include <linux/errno.h>
4531113bbSJens Axboe #include <linux/fs.h>
5531113bbSJens Axboe #include <linux/file.h>
6531113bbSJens Axboe #include <linux/mm.h>
7531113bbSJens Axboe #include <linux/slab.h>
8531113bbSJens Axboe #include <linux/namei.h>
9531113bbSJens Axboe #include <linux/io_uring.h>
10531113bbSJens Axboe #include <linux/splice.h>
11531113bbSJens Axboe 
12531113bbSJens Axboe #include <uapi/linux/io_uring.h>
13531113bbSJens Axboe 
14531113bbSJens Axboe #include "io_uring.h"
15531113bbSJens Axboe #include "splice.h"
16531113bbSJens Axboe 
17531113bbSJens Axboe struct io_splice {
18531113bbSJens Axboe 	struct file			*file_out;
19531113bbSJens Axboe 	loff_t				off_out;
20531113bbSJens Axboe 	loff_t				off_in;
21531113bbSJens Axboe 	u64				len;
22531113bbSJens Axboe 	int				splice_fd_in;
23531113bbSJens Axboe 	unsigned int			flags;
24531113bbSJens Axboe };
25531113bbSJens Axboe 
__io_splice_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)26531113bbSJens Axboe static int __io_splice_prep(struct io_kiocb *req,
27531113bbSJens Axboe 			    const struct io_uring_sqe *sqe)
28531113bbSJens Axboe {
29f2ccb5aeSStefan Metzmacher 	struct io_splice *sp = io_kiocb_to_cmd(req, struct io_splice);
30531113bbSJens Axboe 	unsigned int valid_flags = SPLICE_F_FD_IN_FIXED | SPLICE_F_ALL;
31531113bbSJens Axboe 
32531113bbSJens Axboe 	sp->len = READ_ONCE(sqe->len);
33531113bbSJens Axboe 	sp->flags = READ_ONCE(sqe->splice_flags);
34531113bbSJens Axboe 	if (unlikely(sp->flags & ~valid_flags))
35531113bbSJens Axboe 		return -EINVAL;
36531113bbSJens Axboe 	sp->splice_fd_in = READ_ONCE(sqe->splice_fd_in);
37aebb224fSDylan Yudaken 	req->flags |= REQ_F_FORCE_ASYNC;
38531113bbSJens Axboe 	return 0;
39531113bbSJens Axboe }
40531113bbSJens Axboe 
io_tee_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)41531113bbSJens Axboe int io_tee_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
42531113bbSJens Axboe {
43531113bbSJens Axboe 	if (READ_ONCE(sqe->splice_off_in) || READ_ONCE(sqe->off))
44531113bbSJens Axboe 		return -EINVAL;
45531113bbSJens Axboe 	return __io_splice_prep(req, sqe);
46531113bbSJens Axboe }
47531113bbSJens Axboe 
io_tee(struct io_kiocb * req,unsigned int issue_flags)48531113bbSJens Axboe int io_tee(struct io_kiocb *req, unsigned int issue_flags)
49531113bbSJens Axboe {
50f2ccb5aeSStefan Metzmacher 	struct io_splice *sp = io_kiocb_to_cmd(req, struct io_splice);
51531113bbSJens Axboe 	struct file *out = sp->file_out;
52531113bbSJens Axboe 	unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
53531113bbSJens Axboe 	struct file *in;
54531113bbSJens Axboe 	long ret = 0;
55531113bbSJens Axboe 
56aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
57531113bbSJens Axboe 
58531113bbSJens Axboe 	if (sp->flags & SPLICE_F_FD_IN_FIXED)
59531113bbSJens Axboe 		in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
60531113bbSJens Axboe 	else
61531113bbSJens Axboe 		in = io_file_get_normal(req, sp->splice_fd_in);
62531113bbSJens Axboe 	if (!in) {
63531113bbSJens Axboe 		ret = -EBADF;
64531113bbSJens Axboe 		goto done;
65531113bbSJens Axboe 	}
66531113bbSJens Axboe 
67531113bbSJens Axboe 	if (sp->len)
68531113bbSJens Axboe 		ret = do_tee(in, out, sp->len, flags);
69531113bbSJens Axboe 
70531113bbSJens Axboe 	if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
71*9f69a259SJens Axboe 		fput(in);
72531113bbSJens Axboe done:
73531113bbSJens Axboe 	if (ret != sp->len)
74531113bbSJens Axboe 		req_set_fail(req);
75531113bbSJens Axboe 	io_req_set_res(req, ret, 0);
76531113bbSJens Axboe 	return IOU_OK;
77531113bbSJens Axboe }
78531113bbSJens Axboe 
io_splice_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)79531113bbSJens Axboe int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
80531113bbSJens Axboe {
81f2ccb5aeSStefan Metzmacher 	struct io_splice *sp = io_kiocb_to_cmd(req, struct io_splice);
82531113bbSJens Axboe 
83531113bbSJens Axboe 	sp->off_in = READ_ONCE(sqe->splice_off_in);
84531113bbSJens Axboe 	sp->off_out = READ_ONCE(sqe->off);
85531113bbSJens Axboe 	return __io_splice_prep(req, sqe);
86531113bbSJens Axboe }
87531113bbSJens Axboe 
io_splice(struct io_kiocb * req,unsigned int issue_flags)88531113bbSJens Axboe int io_splice(struct io_kiocb *req, unsigned int issue_flags)
89531113bbSJens Axboe {
90f2ccb5aeSStefan Metzmacher 	struct io_splice *sp = io_kiocb_to_cmd(req, struct io_splice);
91531113bbSJens Axboe 	struct file *out = sp->file_out;
92531113bbSJens Axboe 	unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
93531113bbSJens Axboe 	loff_t *poff_in, *poff_out;
94531113bbSJens Axboe 	struct file *in;
95531113bbSJens Axboe 	long ret = 0;
96531113bbSJens Axboe 
97aebb224fSDylan Yudaken 	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
98531113bbSJens Axboe 
99531113bbSJens Axboe 	if (sp->flags & SPLICE_F_FD_IN_FIXED)
100531113bbSJens Axboe 		in = io_file_get_fixed(req, sp->splice_fd_in, issue_flags);
101531113bbSJens Axboe 	else
102531113bbSJens Axboe 		in = io_file_get_normal(req, sp->splice_fd_in);
103531113bbSJens Axboe 	if (!in) {
104531113bbSJens Axboe 		ret = -EBADF;
105531113bbSJens Axboe 		goto done;
106531113bbSJens Axboe 	}
107531113bbSJens Axboe 
108531113bbSJens Axboe 	poff_in = (sp->off_in == -1) ? NULL : &sp->off_in;
109531113bbSJens Axboe 	poff_out = (sp->off_out == -1) ? NULL : &sp->off_out;
110531113bbSJens Axboe 
111531113bbSJens Axboe 	if (sp->len)
112531113bbSJens Axboe 		ret = do_splice(in, poff_in, out, poff_out, sp->len, flags);
113531113bbSJens Axboe 
114531113bbSJens Axboe 	if (!(sp->flags & SPLICE_F_FD_IN_FIXED))
115*9f69a259SJens Axboe 		fput(in);
116531113bbSJens Axboe done:
117531113bbSJens Axboe 	if (ret != sp->len)
118531113bbSJens Axboe 		req_set_fail(req);
119531113bbSJens Axboe 	io_req_set_res(req, ret, 0);
120531113bbSJens Axboe 	return IOU_OK;
121531113bbSJens Axboe }
122