io_uring: defer splice/tee file validity check until command issue

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>
This commit is contained in:
Jens Axboe 2022-03-29 10:59:20 -06:00
parent ec858afda8
commit a3e4bc23d5

View File

@ -654,10 +654,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;
};
@ -1687,14 +1687,6 @@ static void io_prep_async_work(struct io_kiocb *req)
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)
@ -4369,18 +4361,11 @@ static int __io_splice_prep(struct io_kiocb *req,
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;
}
@ -4395,20 +4380,27 @@ static int io_tee_prep(struct io_kiocb *req,
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);
@ -4427,15 +4419,22 @@ static int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
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;
@ -4444,8 +4443,7 @@ static int io_splice(struct io_kiocb *req, unsigned int issue_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);
@ -7176,11 +7174,6 @@ static void io_clean_op(struct io_kiocb *req)
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)