aboutsummaryrefslogtreecommitdiff
path: root/test/ringbuf-read.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/ringbuf-read.c')
-rw-r--r--test/ringbuf-read.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/test/ringbuf-read.c b/test/ringbuf-read.c
new file mode 100644
index 0000000..673f2de
--- /dev/null
+++ b/test/ringbuf-read.c
@@ -0,0 +1,195 @@
+/* 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, int async)
+{
+ 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, &reg, 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;
+ if (async && !(i & 1))
+ sqe->flags |= IOSQE_ASYNC;
+ sqe->user_data = i + 1;
+ }
+
+ 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, ud;
+
+ 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;
+ ud = cqe->user_data;
+ io_uring_cqe_seen(&ring, cqe);
+ if (verify_buffer(buf + ((bid - 1) * BUF_SIZE), ud))
+ 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, 0);
+ if (ret) {
+ fprintf(stderr, "dio test failed\n");
+ return ret;
+ }
+ if (no_buf_ring)
+ return 0;
+
+ ret = test(fname, 0, 0);
+ if (ret) {
+ fprintf(stderr, "buffered test failed\n");
+ return ret;
+ }
+
+ ret = test(fname, 1, 1);
+ if (ret) {
+ fprintf(stderr, "dio async test failed\n");
+ return ret;
+ }
+
+ ret = test(fname, 0, 1);
+ if (ret) {
+ fprintf(stderr, "buffered async test failed\n");
+ return ret;
+ }
+
+ return 0;
+err:
+ if (do_unlink)
+ unlink(fname);
+ return 1;
+}