diff options
-rw-r--r-- | test/Makefile | 1 | ||||
-rw-r--r-- | test/ringbuf-read.c | 179 |
2 files changed, 180 insertions, 0 deletions
diff --git a/test/Makefile b/test/Makefile index 51c35a9..09e73f9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -126,6 +126,7 @@ test_srcs := \ recv-msgall-stream.c \ register-restrictions.c \ rename.c \ + ringbuf-read.c \ ring-leak2.c \ ring-leak.c \ rsrc_tags.c \ diff --git a/test/ringbuf-read.c b/test/ringbuf-read.c new file mode 100644 index 0000000..f2feba9 --- /dev/null +++ b/test/ringbuf-read.c @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Description: ring mapped provided buffers with reads + * + */ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> + +#include "liburing.h" +#include "helpers.h" + +#define BUF_SIZE 4096 +#define NR_BUFS 64 +#define FSIZE (BUF_SIZE * NR_BUFS) + +#define BR_MASK (NR_BUFS - 1) + +static int no_buf_ring; + +static int verify_buffer(char *buf, char val) +{ + int i; + + for (i = 0; i < BUF_SIZE; i++) { + if (buf[i] != val) { + fprintf(stderr, "got %d, wanted %d\n", buf[i], val); + return 1; + } + } + + return 0; +} + +static int test(const char *filename, int dio) +{ + struct io_uring_buf_reg reg = { }; + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct io_uring ring; + struct io_uring_buf_ring *br; + int ret, fd, i; + char *buf; + void *ptr; + + ret = io_uring_queue_init(NR_BUFS, &ring, 0); + if (ret) { + fprintf(stderr, "ring setup failed: %d\n", ret); + return 1; + } + + if (dio) + fd = open(filename, O_DIRECT | O_RDONLY); + else + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + posix_fadvise(fd, 0, FSIZE, POSIX_FADV_DONTNEED); + + if (posix_memalign((void **) &buf, 4096, FSIZE)) + return 1; + if (posix_memalign((void **) &br, 4096, 4096)) + return 1; + + reg.ring_addr = (unsigned long) br; + reg.ring_entries = NR_BUFS; + reg.bgid = 1; + + ret = io_uring_register_buf_ring(&ring, ®, 0); + if (ret) { + if (ret == -EINVAL) { + no_buf_ring = 1; + return 0; + } + fprintf(stderr, "Buffer ring register failed %d\n", ret); + return 1; + } + + ptr = buf; + for (i = 0; i < NR_BUFS; i++) { + io_uring_buf_ring_add(br, ptr, BUF_SIZE, i + 1, BR_MASK, i); + ptr += BUF_SIZE; + } + io_uring_buf_ring_advance(br, NR_BUFS); + + for (i = 0; i < NR_BUFS; i++) { + sqe = io_uring_get_sqe(&ring); + io_uring_prep_read(sqe, fd, NULL, BUF_SIZE, i * BUF_SIZE); + sqe->buf_group = 1; + sqe->flags |= IOSQE_BUFFER_SELECT; + } + + ret = io_uring_submit(&ring); + if (ret != NR_BUFS) { + fprintf(stderr, "submit: %d\n", ret); + return 1; + } + + for (i = 0; i < NR_BUFS; i++) { + int bid; + + ret = io_uring_wait_cqe(&ring, &cqe); + if (ret) { + fprintf(stderr, "wait cqe failed %d\n", ret); + return 1; + } + if (cqe->res != BUF_SIZE) { + fprintf(stderr, "cqe res %d\n", cqe->res); + return 1; + } + if (!(cqe->flags & IORING_CQE_F_BUFFER)) { + fprintf(stderr, "no buffer selected\n"); + return 1; + } + bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT; + io_uring_cqe_seen(&ring, cqe); + if (verify_buffer(buf + ((bid - 1) * BUF_SIZE), bid)) + return 1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + char buf[BUF_SIZE]; + char fname[80]; + int ret, fd, i, do_unlink; + + if (argc > 1) { + strcpy(fname, argv[1]); + do_unlink = 0; + } else { + sprintf(fname, ".ringbuf-read.%d", getpid()); + t_create_file(fname, FSIZE); + do_unlink = 1; + } + + fd = open(fname, O_WRONLY); + if (fd < 0) { + perror("open"); + goto err; + } + for (i = 0; i < NR_BUFS; i++) { + memset(buf, i + 1, BUF_SIZE); + ret = write(fd, buf, BUF_SIZE); + if (ret != BUF_SIZE) { + fprintf(stderr, "bad file prep write\n"); + goto err; + } + } + close(fd); + + ret = test(fname, 1); + if (ret) { + fprintf(stderr, "dio test failed\n"); + return ret; + } + if (no_buf_ring) + return 0; + + ret = test(fname, 0); + if (ret) { + fprintf(stderr, "buffered test failed\n"); + return ret; + } + + return 0; +err: + if (do_unlink) + unlink(fname); + return 1; +} |