| From a3e4bc23d5470b2beb7cc42a86b6a3e75b704c15 Mon Sep 17 00:00:00 2001 |
| From: Jens Axboe <axboe@kernel.dk> |
| Date: Tue, 29 Mar 2022 10:59:20 -0600 |
| Subject: io_uring: defer splice/tee file validity check until command issue |
| |
| From: Jens Axboe <axboe@kernel.dk> |
| |
| commit a3e4bc23d5470b2beb7cc42a86b6a3e75b704c15 upstream. |
| |
| In preparation for not using the file at prep time, defer checking if this |
| file refers to a valid io_uring instance until issue time. |
| |
| This also means we can get rid of the cleanup flag for splice and tee. |
| |
| Cc: stable@vger.kernel.org # v5.15+ |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/io_uring.c | 49 +++++++++++++++++++++---------------------------- |
| 1 file changed, 21 insertions(+), 28 deletions(-) |
| |
| --- a/fs/io_uring.c |
| +++ b/fs/io_uring.c |
| @@ -619,10 +619,10 @@ struct io_epoll { |
| |
| struct io_splice { |
| struct file *file_out; |
| - struct file *file_in; |
| loff_t off_out; |
| loff_t off_in; |
| u64 len; |
| + int splice_fd_in; |
| unsigned int flags; |
| }; |
| |
| @@ -1524,14 +1524,6 @@ static void io_prep_async_work(struct io |
| if (def->unbound_nonreg_file) |
| req->work.flags |= IO_WQ_WORK_UNBOUND; |
| } |
| - |
| - switch (req->opcode) { |
| - case IORING_OP_SPLICE: |
| - case IORING_OP_TEE: |
| - if (!S_ISREG(file_inode(req->splice.file_in)->i_mode)) |
| - req->work.flags |= IO_WQ_WORK_UNBOUND; |
| - break; |
| - } |
| } |
| |
| static void io_prep_async_link(struct io_kiocb *req) |
| @@ -4054,18 +4046,11 @@ static int __io_splice_prep(struct io_ki |
| if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL)) |
| return -EINVAL; |
| |
| - sp->file_in = NULL; |
| sp->len = READ_ONCE(sqe->len); |
| sp->flags = READ_ONCE(sqe->splice_flags); |
| - |
| if (unlikely(sp->flags & ~valid_flags)) |
| return -EINVAL; |
| - |
| - sp->file_in = io_file_get(req->ctx, req, READ_ONCE(sqe->splice_fd_in), |
| - (sp->flags & SPLICE_F_FD_IN_FIXED)); |
| - if (!sp->file_in) |
| - return -EBADF; |
| - req->flags |= REQ_F_NEED_CLEANUP; |
| + sp->splice_fd_in = READ_ONCE(sqe->splice_fd_in); |
| return 0; |
| } |
| |
| @@ -4080,20 +4065,27 @@ static int io_tee_prep(struct io_kiocb * |
| static int io_tee(struct io_kiocb *req, unsigned int issue_flags) |
| { |
| struct io_splice *sp = &req->splice; |
| - struct file *in = sp->file_in; |
| 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; |
| + |
| + in = io_file_get(req->ctx, req, sp->splice_fd_in, |
| + (sp->flags & SPLICE_F_FD_IN_FIXED)); |
| + 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); |
| - req->flags &= ~REQ_F_NEED_CLEANUP; |
| - |
| +done: |
| if (ret != sp->len) |
| req_set_fail(req); |
| io_req_complete(req, ret); |
| @@ -4112,15 +4104,22 @@ static int io_splice_prep(struct io_kioc |
| static int io_splice(struct io_kiocb *req, unsigned int issue_flags) |
| { |
| struct io_splice *sp = &req->splice; |
| - struct file *in = sp->file_in; |
| 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; |
| |
| + in = io_file_get(req->ctx, req, sp->splice_fd_in, |
| + (sp->flags & SPLICE_F_FD_IN_FIXED)); |
| + 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; |
| |
| @@ -4129,8 +4128,7 @@ static int io_splice(struct io_kiocb *re |
| |
| if (!(sp->flags & SPLICE_F_FD_IN_FIXED)) |
| io_put_file(in); |
| - req->flags &= ~REQ_F_NEED_CLEANUP; |
| - |
| +done: |
| if (ret != sp->len) |
| req_set_fail(req); |
| io_req_complete(req, ret); |
| @@ -6630,11 +6628,6 @@ static void io_clean_op(struct io_kiocb |
| kfree(io->free_iov); |
| break; |
| } |
| - case IORING_OP_SPLICE: |
| - case IORING_OP_TEE: |
| - if (!(req->splice.flags & SPLICE_F_FD_IN_FIXED)) |
| - io_put_file(req->splice.file_in); |
| - break; |
| case IORING_OP_OPENAT: |
| case IORING_OP_OPENAT2: |
| if (req->open.filename) |