io_uring: add non-vectored read/write commands
For uses cases that don't already naturally have an iovec, it's easier (or more convenient) to just use a buffer address + length. This is particular true if the use case is from languages that want to create a memory safe abstraction on top of io_uring, and where introducing the need for the iovec may impose an ownership issue. For those cases, they currently need an indirection buffer, which means allocating data just for this purpose. Add basic read/write that don't require the iovec. Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
e94f141bd2
commit
3a6820f2bb
|
@ -654,6 +654,18 @@ static const struct io_op_def io_op_defs[] = {
|
||||||
.needs_file = 1,
|
.needs_file = 1,
|
||||||
.fd_non_neg = 1,
|
.fd_non_neg = 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
/* IORING_OP_READ */
|
||||||
|
.needs_mm = 1,
|
||||||
|
.needs_file = 1,
|
||||||
|
.unbound_nonreg_file = 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* IORING_OP_WRITE */
|
||||||
|
.needs_mm = 1,
|
||||||
|
.needs_file = 1,
|
||||||
|
.unbound_nonreg_file = 1,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void io_wq_submit_work(struct io_wq_work **workptr);
|
static void io_wq_submit_work(struct io_wq_work **workptr);
|
||||||
|
@ -1867,6 +1879,13 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
|
||||||
if (req->rw.kiocb.private)
|
if (req->rw.kiocb.private)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (opcode == IORING_OP_READ || opcode == IORING_OP_WRITE) {
|
||||||
|
ssize_t ret;
|
||||||
|
ret = import_single_range(rw, buf, sqe_len, *iovec, iter);
|
||||||
|
*iovec = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (req->io) {
|
if (req->io) {
|
||||||
struct io_async_rw *iorw = &req->io->rw;
|
struct io_async_rw *iorw = &req->io->rw;
|
||||||
|
|
||||||
|
@ -3634,10 +3653,12 @@ static int io_req_defer_prep(struct io_kiocb *req,
|
||||||
break;
|
break;
|
||||||
case IORING_OP_READV:
|
case IORING_OP_READV:
|
||||||
case IORING_OP_READ_FIXED:
|
case IORING_OP_READ_FIXED:
|
||||||
|
case IORING_OP_READ:
|
||||||
ret = io_read_prep(req, sqe, true);
|
ret = io_read_prep(req, sqe, true);
|
||||||
break;
|
break;
|
||||||
case IORING_OP_WRITEV:
|
case IORING_OP_WRITEV:
|
||||||
case IORING_OP_WRITE_FIXED:
|
case IORING_OP_WRITE_FIXED:
|
||||||
|
case IORING_OP_WRITE:
|
||||||
ret = io_write_prep(req, sqe, true);
|
ret = io_write_prep(req, sqe, true);
|
||||||
break;
|
break;
|
||||||
case IORING_OP_POLL_ADD:
|
case IORING_OP_POLL_ADD:
|
||||||
|
@ -3741,6 +3762,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
|
||||||
break;
|
break;
|
||||||
case IORING_OP_READV:
|
case IORING_OP_READV:
|
||||||
case IORING_OP_READ_FIXED:
|
case IORING_OP_READ_FIXED:
|
||||||
|
case IORING_OP_READ:
|
||||||
if (sqe) {
|
if (sqe) {
|
||||||
ret = io_read_prep(req, sqe, force_nonblock);
|
ret = io_read_prep(req, sqe, force_nonblock);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -3750,6 +3772,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
|
||||||
break;
|
break;
|
||||||
case IORING_OP_WRITEV:
|
case IORING_OP_WRITEV:
|
||||||
case IORING_OP_WRITE_FIXED:
|
case IORING_OP_WRITE_FIXED:
|
||||||
|
case IORING_OP_WRITE:
|
||||||
if (sqe) {
|
if (sqe) {
|
||||||
ret = io_write_prep(req, sqe, force_nonblock);
|
ret = io_write_prep(req, sqe, force_nonblock);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -84,6 +84,8 @@ enum {
|
||||||
IORING_OP_CLOSE,
|
IORING_OP_CLOSE,
|
||||||
IORING_OP_FILES_UPDATE,
|
IORING_OP_FILES_UPDATE,
|
||||||
IORING_OP_STATX,
|
IORING_OP_STATX,
|
||||||
|
IORING_OP_READ,
|
||||||
|
IORING_OP_WRITE,
|
||||||
|
|
||||||
/* this goes last, obviously */
|
/* this goes last, obviously */
|
||||||
IORING_OP_LAST,
|
IORING_OP_LAST,
|
||||||
|
|
Loading…
Reference in a new issue