summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2020-05-19 18:41:57 -0600
committerJens Axboe <axboe@kernel.dk>2020-05-19 18:41:57 -0600
commitc4170854a19eec186ac6565490a353987e37548b (patch)
tree3bb0ca22feaab93a736650e277733c922f990707 /test
parentbd1cc8f03cff0ca66e212688979f8e82abb31dab (diff)
downloadliburing-c4170854a19eec186ac6565490a353987e37548b.tar.gz
liburing-c4170854a19eec186ac6565490a353987e37548b.tar.bz2
test/iopoll: add polled IO test case
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'test')
-rw-r--r--test/Makefile4
-rw-r--r--test/iopoll.c251
2 files changed, 253 insertions, 2 deletions
diff --git a/test/Makefile b/test/Makefile
index ff4d4b8..3b5e19f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -21,7 +21,7 @@ all_targets += poll poll-cancel ring-leak fsync io_uring_setup io_uring_register
file-update accept-reuse poll-v-poll fadvise madvise \
short-read openat2 probe shared-wq personality eventfd \
send_recv eventfd-ring across-fork sq-poll-kthread splice \
- lfs-openat lfs-openat-write
+ lfs-openat lfs-openat-write iopoll
include ../Makefile.quiet
@@ -53,7 +53,7 @@ test_srcs := poll.c poll-cancel.c ring-leak.c fsync.c io_uring_setup.c \
file-update.c accept-reuse.c poll-v-poll.c fadvise.c \
madvise.c short-read.c openat2.c probe.c shared-wq.c \
personality.c eventfd.c eventfd-ring.c across-fork.c sq-poll-kthread.c \
- splice.c lfs-openat.c lfs-openat-write.c
+ splice.c lfs-openat.c lfs-openat-write.c iopoll.c
ifdef CONFIG_HAVE_STATX
test_srcs += statx.c
diff --git a/test/iopoll.c b/test/iopoll.c
new file mode 100644
index 0000000..29955b2
--- /dev/null
+++ b/test/iopoll.c
@@ -0,0 +1,251 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: basic read/write tests with polled IO
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <sys/eventfd.h>
+#include <sys/resource.h>
+#include "liburing.h"
+
+#define FILE_SIZE (128 * 1024)
+#define BS 4096
+#define BUFFERS (FILE_SIZE / BS)
+
+static struct iovec *vecs;
+
+static int create_buffers(void)
+{
+ int i;
+
+ vecs = malloc(BUFFERS * sizeof(struct iovec));
+ for (i = 0; i < BUFFERS; i++) {
+ if (posix_memalign(&vecs[i].iov_base, BS, BS))
+ return 1;
+ vecs[i].iov_len = BS;
+ }
+
+ return 0;
+}
+
+static int create_file(const char *file)
+{
+ ssize_t ret;
+ char *buf;
+ int fd;
+
+ buf = malloc(FILE_SIZE);
+ memset(buf, 0xaa, FILE_SIZE);
+
+ fd = open(file, O_WRONLY | O_CREAT, 0644);
+ if (fd < 0) {
+ perror("open file");
+ return 1;
+ }
+ ret = write(fd, buf, FILE_SIZE);
+ close(fd);
+ return ret != FILE_SIZE;
+}
+
+static int __test_io(const char *file, struct io_uring *ring, int write, int sqthread,
+ int fixed)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int open_flags;
+ int i, fd, ret;
+ off_t offset;
+
+ if (write)
+ open_flags = O_WRONLY;
+ else
+ open_flags = O_RDONLY;
+ open_flags |= O_DIRECT;
+
+ fd = open(file, open_flags);
+ if (fd < 0) {
+ perror("file open");
+ goto err;
+ }
+
+ if (fixed) {
+ ret = io_uring_register_buffers(ring, vecs, BUFFERS);
+ if (ret) {
+ fprintf(stderr, "buffer reg failed: %d\n", ret);
+ goto err;
+ }
+ }
+ if (sqthread) {
+ ret = io_uring_register_files(ring, &fd, 1);
+ if (ret) {
+ fprintf(stderr, "file reg failed: %d\n", ret);
+ goto err;
+ }
+ }
+
+ offset = 0;
+ for (i = 0; i < BUFFERS; i++) {
+ sqe = io_uring_get_sqe(ring);
+ if (!sqe) {
+ fprintf(stderr, "sqe get failed\n");
+ goto err;
+ }
+ offset = BS * (rand() % BUFFERS);
+ if (write) {
+ int do_fixed = fixed;
+ int use_fd = fd;
+
+ if (sqthread)
+ use_fd = 0;
+ if (fixed && (i & 1))
+ do_fixed = 0;
+ if (do_fixed) {
+ io_uring_prep_write_fixed(sqe, use_fd, vecs[i].iov_base,
+ vecs[i].iov_len,
+ offset, i);
+ } else {
+ io_uring_prep_writev(sqe, use_fd, &vecs[i], 1,
+ offset);
+ }
+ } else {
+ int do_fixed = fixed;
+ int use_fd = fd;
+
+ if (sqthread)
+ use_fd = 0;
+ if (fixed && (i & 1))
+ do_fixed = 0;
+ if (do_fixed) {
+ io_uring_prep_read_fixed(sqe, use_fd, vecs[i].iov_base,
+ vecs[i].iov_len,
+ offset, i);
+ } else {
+ io_uring_prep_readv(sqe, use_fd, &vecs[i], 1,
+ offset);
+ }
+
+ }
+ if (sqthread)
+ sqe->flags |= IOSQE_FIXED_FILE;
+ }
+
+ ret = io_uring_submit(ring);
+ if (ret != BUFFERS) {
+ fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
+ goto err;
+ }
+
+ for (i = 0; i < BUFFERS; i++) {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe=%d\n", ret);
+ goto err;
+ } else if (cqe->res != BS) {
+ fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res, BS);
+ goto err;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ if (fixed) {
+ ret = io_uring_unregister_buffers(ring);
+ if (ret) {
+ fprintf(stderr, "buffer unreg failed: %d\n", ret);
+ goto err;
+ }
+ }
+ if (sqthread) {
+ ret = io_uring_unregister_files(ring);
+ if (ret) {
+ fprintf(stderr, "file unreg failed: %d\n", ret);
+ goto err;
+ }
+ }
+
+ close(fd);
+#ifdef VERBOSE
+ fprintf(stdout, "PASS\n");
+#endif
+ return 0;
+err:
+#ifdef VERBOSE
+ fprintf(stderr, "FAILED\n");
+#endif
+ if (fd != -1)
+ close(fd);
+ return 1;
+}
+
+static int test_io(const char *file, int write, int sqthread, int fixed)
+{
+ struct io_uring ring;
+ int ret, ring_flags;
+
+ ring_flags = IORING_SETUP_IOPOLL;
+ if (sqthread)
+ ring_flags |= IORING_SETUP_SQPOLL;
+
+ ret = io_uring_queue_init(64, &ring, ring_flags);
+ if (ret) {
+ fprintf(stderr, "ring create failed: %d\n", ret);
+ return 1;
+ }
+
+ ret = __test_io(file, &ring, write, sqthread, fixed);
+
+ io_uring_queue_exit(&ring);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int i, ret;
+ char *fname;
+
+ if (geteuid()) {
+ fprintf(stdout, "iopoll requires root, skipping\n");
+ return 0;
+ }
+
+ if (argc > 1) {
+ fname = argv[1];
+ } else {
+ fname = ".iopoll-rw";
+ if (create_file(".iopoll-rw")) {
+ fprintf(stderr, "file creation failed\n");
+ goto err;
+ }
+ }
+
+ if (create_buffers()) {
+ fprintf(stderr, "file creation failed\n");
+ goto err;
+ }
+
+ for (i = 0; i < 16; i++) {
+ int v1, v2, v3;
+
+ v1 = (i & 1) != 0;
+ v2 = (i & 2) != 0;
+ v3 = (i & 4) != 0;
+ ret = test_io(fname, v1, v2, v3);
+ if (ret) {
+ fprintf(stderr, "test_io failed %d/%d/%d\n", v1, v2, v3);
+ goto err;
+ }
+ }
+
+ if (fname != argv[1])
+ unlink(fname);
+ return 0;
+err:
+ if (fname != argv[1])
+ unlink(fname);
+ return 1;
+}