io_uring/rw: implement vectored registered rw
Implement registered buffer vectored reads with new opcodes IORING_OP_WRITEV_FIXED and IORING_OP_READV_FIXED. Signed-off-by: Pavel Begunkov <asml.silence@gmail.com> Link: https://lore.kernel.org/r/d7c89eb481e870f598edc91cc66ff4d1e4ae3788.1741362889.git.asml.silence@gmail.com Signed-off-by: Jens Axboe <axboe@kernel.dk>pull/1188/head
parent
9ef4cbbcb4
commit
bdabba04bb
|
|
@ -281,6 +281,8 @@ enum io_uring_op {
|
|||
IORING_OP_LISTEN,
|
||||
IORING_OP_RECV_ZC,
|
||||
IORING_OP_EPOLL_WAIT,
|
||||
IORING_OP_READV_FIXED,
|
||||
IORING_OP_WRITEV_FIXED,
|
||||
|
||||
/* this goes last, obviously */
|
||||
IORING_OP_LAST,
|
||||
|
|
|
|||
|
|
@ -540,6 +540,35 @@ const struct io_issue_def io_issue_defs[] = {
|
|||
.prep = io_eopnotsupp_prep,
|
||||
#endif
|
||||
},
|
||||
[IORING_OP_READV_FIXED] = {
|
||||
.needs_file = 1,
|
||||
.unbound_nonreg_file = 1,
|
||||
.pollin = 1,
|
||||
.plug = 1,
|
||||
.audit_skip = 1,
|
||||
.ioprio = 1,
|
||||
.iopoll = 1,
|
||||
.iopoll_queue = 1,
|
||||
.vectored = 1,
|
||||
.async_size = sizeof(struct io_async_rw),
|
||||
.prep = io_prep_readv_fixed,
|
||||
.issue = io_read,
|
||||
},
|
||||
[IORING_OP_WRITEV_FIXED] = {
|
||||
.needs_file = 1,
|
||||
.hash_reg_file = 1,
|
||||
.unbound_nonreg_file = 1,
|
||||
.pollout = 1,
|
||||
.plug = 1,
|
||||
.audit_skip = 1,
|
||||
.ioprio = 1,
|
||||
.iopoll = 1,
|
||||
.iopoll_queue = 1,
|
||||
.vectored = 1,
|
||||
.async_size = sizeof(struct io_async_rw),
|
||||
.prep = io_prep_writev_fixed,
|
||||
.issue = io_write,
|
||||
},
|
||||
};
|
||||
|
||||
const struct io_cold_def io_cold_defs[] = {
|
||||
|
|
@ -775,6 +804,16 @@ const struct io_cold_def io_cold_defs[] = {
|
|||
[IORING_OP_EPOLL_WAIT] = {
|
||||
.name = "EPOLL_WAIT",
|
||||
},
|
||||
[IORING_OP_READV_FIXED] = {
|
||||
.name = "READV_FIXED",
|
||||
.cleanup = io_readv_writev_cleanup,
|
||||
.fail = io_rw_fail,
|
||||
},
|
||||
[IORING_OP_WRITEV_FIXED] = {
|
||||
.name = "WRITEV_FIXED",
|
||||
.cleanup = io_readv_writev_cleanup,
|
||||
.fail = io_rw_fail,
|
||||
},
|
||||
};
|
||||
|
||||
const char *io_uring_get_opcode(u8 opcode)
|
||||
|
|
|
|||
|
|
@ -381,6 +381,57 @@ int io_prep_write_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
return __io_prep_rw(req, sqe, ITER_SOURCE);
|
||||
}
|
||||
|
||||
static int io_rw_prep_reg_vec(struct io_kiocb *req, int ddir)
|
||||
{
|
||||
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
|
||||
struct io_async_rw *io = req->async_data;
|
||||
const struct iovec __user *uvec;
|
||||
size_t uvec_segs = rw->len;
|
||||
struct iovec *iov;
|
||||
int iovec_off, ret;
|
||||
void *res;
|
||||
|
||||
if (uvec_segs > io->vec.nr) {
|
||||
ret = io_vec_realloc(&io->vec, uvec_segs);
|
||||
if (ret)
|
||||
return ret;
|
||||
req->flags |= REQ_F_NEED_CLEANUP;
|
||||
}
|
||||
/* pad iovec to the right */
|
||||
iovec_off = io->vec.nr - uvec_segs;
|
||||
iov = io->vec.iovec + iovec_off;
|
||||
uvec = u64_to_user_ptr(rw->addr);
|
||||
res = iovec_from_user(uvec, uvec_segs, uvec_segs, iov,
|
||||
io_is_compat(req->ctx));
|
||||
if (IS_ERR(res))
|
||||
return PTR_ERR(res);
|
||||
|
||||
ret = io_import_reg_vec(ddir, &io->iter, req, &io->vec,
|
||||
uvec_segs, iovec_off, 0);
|
||||
iov_iter_save_state(&io->iter, &io->iter_state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int io_prep_readv_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __io_prep_rw(req, sqe, ITER_DEST);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
return io_rw_prep_reg_vec(req, ITER_DEST);
|
||||
}
|
||||
|
||||
int io_prep_writev_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __io_prep_rw(req, sqe, ITER_SOURCE);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
return io_rw_prep_reg_vec(req, ITER_SOURCE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Multishot read is prepared just like a normal read/write request, only
|
||||
* difference is that we set the MULTISHOT flag.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ struct io_async_rw {
|
|||
|
||||
int io_prep_read_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||
int io_prep_write_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||
int io_prep_readv_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||
int io_prep_writev_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||
int io_prep_readv(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||
int io_prep_writev(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||
int io_prep_read(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||
|
|
|
|||
Loading…
Reference in New Issue