Async reads had a bug with buffer selection. Add a regression test for this. It fails without the kernel commit: "io_uring: fix provided buffer import" Signed-off-by: Dylan Yudaken <dylany@xxxxxx> --- test/read-write.c | 101 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/test/read-write.c b/test/read-write.c index 3951a64..eadeb78 100644 --- a/test/read-write.c +++ b/test/read-write.c @@ -428,25 +428,28 @@ static int test_buf_select_short(const char *filename, int nonvec) return ret; } -static int provide_buffers_iovec(struct io_uring *ring, int bgid) +static int provide_buffers_iovec(struct io_uring *ring, int bgid, int count) { struct io_uring_sqe *sqe; struct io_uring_cqe *cqe; int i, ret; - for (i = 0; i < BUFFERS; i++) { + if (count <= 0) + count = BUFFERS; + + for (i = 0; i < count; i++) { sqe = io_uring_get_sqe(ring); io_uring_prep_provide_buffers(sqe, vecs[i].iov_base, vecs[i].iov_len, 1, bgid, i); } ret = io_uring_submit(ring); - if (ret != BUFFERS) { + if (ret != count) { fprintf(stderr, "submit: %d\n", ret); return -1; } - for (i = 0; i < BUFFERS; i++) { + for (i = 0; i < count; i++) { ret = io_uring_wait_cqe(ring, &cqe); if (ret) { fprintf(stderr, "wait_cqe=%d\n", ret); @@ -462,6 +465,86 @@ static int provide_buffers_iovec(struct io_uring *ring, int bgid) return 0; } +static int test_buf_select_pipe(void) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct io_uring ring; + int ret, i; + int fds[2]; + + if (no_buf_select) + return 0; + + ret = io_uring_queue_init(64, &ring, 0); + if (ret) { + fprintf(stderr, "ring create failed: %d\n", ret); + return 1; + } + + ret = provide_buffers_iovec(&ring, 0, 4); + if (ret) { + fprintf(stderr, "provide buffers failed: %d\n", ret); + return 1; + } + + ret = pipe(fds); + if (ret) { + fprintf(stderr, "pipe failed: %d\n", ret); + return 1; + } + + for (i = 0; i < 5; i++) { + sqe = io_uring_get_sqe(&ring); + io_uring_prep_read(sqe, fds[0], NULL, 1 /* max read 1 per go */, -1); + sqe->flags |= IOSQE_BUFFER_SELECT; + sqe->buf_group = 0; + } + io_uring_submit(&ring); + + ret = write(fds[1], "01234", 5); + if (ret != 5) { + fprintf(stderr, "pipe write failed %d\n", ret); + return 1; + } + + for (i = 0; i < 5; i++) { + const char *buff; + + if (io_uring_wait_cqe(&ring, &cqe)) { + fprintf(stderr, "bad wait %d\n", i); + return 1; + } + if (i == 4) { + if (cqe->res != -ENOBUFS) { + fprintf(stderr, "expected failure %d\n", cqe->res); + return 1; + } + continue; + } + if (cqe->res != 1) { + fprintf(stderr, "expected read %d\n", cqe->res); + return 1; + } + if (!(cqe->flags & IORING_CQE_F_BUFFER)) { + fprintf(stderr, "no buffer %d\n", cqe->res); + return 1; + } + buff = vecs[cqe->flags >> 16].iov_base; + if (*buff != '0' + i) { + fprintf(stderr, "%d: expected %c, got %c\n", i, '0' + i, *buff); + return 1; + } + io_uring_cqe_seen(&ring, cqe); + } + + + close(fds[0]); + close(fds[1]); + io_uring_queue_exit(&ring); + return 0; +} + static int test_buf_select(const char *filename, int nonvec) { struct io_uring_probe *p; @@ -497,7 +580,7 @@ static int test_buf_select(const char *filename, int nonvec) for (i = 0; i < BUFFERS; i++) memset(vecs[i].iov_base, 0x55, vecs[i].iov_len); - ret = provide_buffers_iovec(&ring, 1); + ret = provide_buffers_iovec(&ring, 1, -1); if (ret) return ret; @@ -523,7 +606,7 @@ static int test_rem_buf(int batch, int sqe_flags) return 1; } - ret = provide_buffers_iovec(&ring, bgid); + ret = provide_buffers_iovec(&ring, bgid, -1); if (ret) return ret; @@ -791,6 +874,12 @@ int main(int argc, char *argv[]) goto err; } + ret = test_buf_select_pipe(); + if (ret) { + fprintf(stderr, "test_buf_select_pipe failed\n"); + goto err; + } + ret = test_eventfd_read(); if (ret) { fprintf(stderr, "test_eventfd_read failed\n"); base-commit: 70e11b3d79714c287c1a03e96eddd957474901dd -- 2.30.2