Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Pavel Begunkov and committed by
Jens Axboe
bdabba04 9ef4cbbc

+94
+2
include/uapi/linux/io_uring.h
··· 281 281 IORING_OP_LISTEN, 282 282 IORING_OP_RECV_ZC, 283 283 IORING_OP_EPOLL_WAIT, 284 + IORING_OP_READV_FIXED, 285 + IORING_OP_WRITEV_FIXED, 284 286 285 287 /* this goes last, obviously */ 286 288 IORING_OP_LAST,
+39
io_uring/opdef.c
··· 540 540 .prep = io_eopnotsupp_prep, 541 541 #endif 542 542 }, 543 + [IORING_OP_READV_FIXED] = { 544 + .needs_file = 1, 545 + .unbound_nonreg_file = 1, 546 + .pollin = 1, 547 + .plug = 1, 548 + .audit_skip = 1, 549 + .ioprio = 1, 550 + .iopoll = 1, 551 + .iopoll_queue = 1, 552 + .vectored = 1, 553 + .async_size = sizeof(struct io_async_rw), 554 + .prep = io_prep_readv_fixed, 555 + .issue = io_read, 556 + }, 557 + [IORING_OP_WRITEV_FIXED] = { 558 + .needs_file = 1, 559 + .hash_reg_file = 1, 560 + .unbound_nonreg_file = 1, 561 + .pollout = 1, 562 + .plug = 1, 563 + .audit_skip = 1, 564 + .ioprio = 1, 565 + .iopoll = 1, 566 + .iopoll_queue = 1, 567 + .vectored = 1, 568 + .async_size = sizeof(struct io_async_rw), 569 + .prep = io_prep_writev_fixed, 570 + .issue = io_write, 571 + }, 543 572 }; 544 573 545 574 const struct io_cold_def io_cold_defs[] = { ··· 803 774 }, 804 775 [IORING_OP_EPOLL_WAIT] = { 805 776 .name = "EPOLL_WAIT", 777 + }, 778 + [IORING_OP_READV_FIXED] = { 779 + .name = "READV_FIXED", 780 + .cleanup = io_readv_writev_cleanup, 781 + .fail = io_rw_fail, 782 + }, 783 + [IORING_OP_WRITEV_FIXED] = { 784 + .name = "WRITEV_FIXED", 785 + .cleanup = io_readv_writev_cleanup, 786 + .fail = io_rw_fail, 806 787 }, 807 788 }; 808 789
+51
io_uring/rw.c
··· 381 381 return __io_prep_rw(req, sqe, ITER_SOURCE); 382 382 } 383 383 384 + static int io_rw_prep_reg_vec(struct io_kiocb *req, int ddir) 385 + { 386 + struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw); 387 + struct io_async_rw *io = req->async_data; 388 + const struct iovec __user *uvec; 389 + size_t uvec_segs = rw->len; 390 + struct iovec *iov; 391 + int iovec_off, ret; 392 + void *res; 393 + 394 + if (uvec_segs > io->vec.nr) { 395 + ret = io_vec_realloc(&io->vec, uvec_segs); 396 + if (ret) 397 + return ret; 398 + req->flags |= REQ_F_NEED_CLEANUP; 399 + } 400 + /* pad iovec to the right */ 401 + iovec_off = io->vec.nr - uvec_segs; 402 + iov = io->vec.iovec + iovec_off; 403 + uvec = u64_to_user_ptr(rw->addr); 404 + res = iovec_from_user(uvec, uvec_segs, uvec_segs, iov, 405 + io_is_compat(req->ctx)); 406 + if (IS_ERR(res)) 407 + return PTR_ERR(res); 408 + 409 + ret = io_import_reg_vec(ddir, &io->iter, req, &io->vec, 410 + uvec_segs, iovec_off, 0); 411 + iov_iter_save_state(&io->iter, &io->iter_state); 412 + return ret; 413 + } 414 + 415 + int io_prep_readv_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe) 416 + { 417 + int ret; 418 + 419 + ret = __io_prep_rw(req, sqe, ITER_DEST); 420 + if (unlikely(ret)) 421 + return ret; 422 + return io_rw_prep_reg_vec(req, ITER_DEST); 423 + } 424 + 425 + int io_prep_writev_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe) 426 + { 427 + int ret; 428 + 429 + ret = __io_prep_rw(req, sqe, ITER_SOURCE); 430 + if (unlikely(ret)) 431 + return ret; 432 + return io_rw_prep_reg_vec(req, ITER_SOURCE); 433 + } 434 + 384 435 /* 385 436 * Multishot read is prepared just like a normal read/write request, only 386 437 * difference is that we set the MULTISHOT flag.
+2
io_uring/rw.h
··· 32 32 33 33 int io_prep_read_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe); 34 34 int io_prep_write_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe); 35 + int io_prep_readv_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe); 36 + int io_prep_writev_fixed(struct io_kiocb *req, const struct io_uring_sqe *sqe); 35 37 int io_prep_readv(struct io_kiocb *req, const struct io_uring_sqe *sqe); 36 38 int io_prep_writev(struct io_kiocb *req, const struct io_uring_sqe *sqe); 37 39 int io_prep_read(struct io_kiocb *req, const struct io_uring_sqe *sqe);