mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	io_uring: split out splice related operations
This splits out splice and tee support. Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
		
							parent
							
								
									11aeb71406
								
							
						
					
					
						commit
						531113bbd5
					
				
					 5 changed files with 154 additions and 130 deletions
				
			
		|  | @ -2,5 +2,5 @@ | ||||||
| #
 | #
 | ||||||
| # Makefile for io_uring
 | # 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 | obj-$(CONFIG_IO_WQ)		+= io-wq.o | ||||||
|  |  | ||||||
|  | @ -95,6 +95,7 @@ | ||||||
| #include "xattr.h" | #include "xattr.h" | ||||||
| #include "nop.h" | #include "nop.h" | ||||||
| #include "fs.h" | #include "fs.h" | ||||||
|  | #include "splice.h" | ||||||
| 
 | 
 | ||||||
| #define IORING_MAX_ENTRIES	32768 | #define IORING_MAX_ENTRIES	32768 | ||||||
| #define IORING_MAX_CQ_ENTRIES	(2 * IORING_MAX_ENTRIES) | #define IORING_MAX_CQ_ENTRIES	(2 * IORING_MAX_ENTRIES) | ||||||
|  | @ -436,15 +437,6 @@ struct io_epoll { | ||||||
| 	struct epoll_event		event; | 	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 io_provide_buf { | ||||||
| 	struct file			*file; | 	struct file			*file; | ||||||
| 	__u64				addr; | 	__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, | 				     struct io_uring_rsrc_update2 *up, | ||||||
| 				     unsigned nr_args); | 				     unsigned nr_args); | ||||||
| static void io_clean_op(struct io_kiocb *req); | 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_queue_sqe(struct io_kiocb *req); | ||||||
| static void io_rsrc_put_work(struct work_struct *work); | 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; | 	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) | static inline void req_fail_link_node(struct io_kiocb *req, int res) | ||||||
| { | { | ||||||
| 	req_set_fail(req); | 	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); | 	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) | static inline void io_dismantle_req(struct io_kiocb *req) | ||||||
| { | { | ||||||
| 	unsigned int flags = req->flags; | 	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; | 	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, | static int io_msg_ring_prep(struct io_kiocb *req, | ||||||
| 			    const struct io_uring_sqe *sqe) | 			    const struct io_uring_sqe *sqe) | ||||||
| { | { | ||||||
|  | @ -7157,7 +7032,7 @@ static void io_fixed_file_set(struct io_fixed_file *file_slot, struct file *file | ||||||
| 	file_slot->file_ptr = file_ptr; | 	file_slot->file_ptr = file_ptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd, | inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd, | ||||||
| 				      unsigned int issue_flags) | 				      unsigned int issue_flags) | ||||||
| { | { | ||||||
| 	struct io_ring_ctx *ctx = req->ctx; | 	struct io_ring_ctx *ctx = req->ctx; | ||||||
|  | @ -7181,7 +7056,7 @@ out: | ||||||
| 	return file; | 	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); | 	struct file *file = fget(fd); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9,10 +9,29 @@ enum { | ||||||
| 	IOU_ISSUE_SKIP_COMPLETE	= -EIOCBQUEUED, | 	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) | static inline void io_req_set_res(struct io_kiocb *req, s32 res, u32 cflags) | ||||||
| { | { | ||||||
| 	req->cqe.res = res; | 	req->cqe.res = res; | ||||||
| 	req->cqe.flags = cflags; | 	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 | #endif | ||||||
|  |  | ||||||
							
								
								
									
										123
									
								
								io_uring/splice.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								io_uring/splice.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								io_uring/splice.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								io_uring/splice.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Jens Axboe
						Jens Axboe