/* SPDX-License-Identifier: MIT */ #include #include #include #include #include #include #include #include #include "liburing.h" #include "test.h" #include "helpers.h" static pid_t pid; static pid_t fork_t(void) { pid = fork(); if (pid == -1) { fprintf(stderr, "fork failed\n"); exit(T_EXIT_FAIL); } return pid; } static void wait_child_t(void) { int wstatus; if (waitpid(pid, &wstatus, 0) == (pid_t)-1) { perror("waitpid()"); exit(T_EXIT_FAIL); } if (!WIFEXITED(wstatus)) { fprintf(stderr, "child failed %i\n", WEXITSTATUS(wstatus)); exit(T_EXIT_FAIL); } if (WEXITSTATUS(wstatus)) exit(T_EXIT_FAIL); } static int try_submit(struct io_uring *ring) { struct io_uring_cqe *cqe; struct io_uring_sqe *sqe; int ret; sqe = io_uring_get_sqe(ring); io_uring_prep_nop(sqe); sqe->user_data = 42; ret = io_uring_submit(ring); if (ret < 0) return ret; if (ret != 1) t_error(1, ret, "submit %i", ret); ret = io_uring_wait_cqe(ring, &cqe); if (ret) t_error(1, ret, "wait fail %i", ret); if (cqe->res || cqe->user_data != 42) t_error(1, ret, "invalid cqe"); io_uring_cqe_seen(ring, cqe); return 0; } int main(int argc, char *argv[]) { struct io_uring ring; int ret; if (argc > 1) return T_EXIT_SKIP; ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER); if (ret == -EINVAL) { return T_EXIT_SKIP; } else if (ret) { fprintf(stderr, "io_uring_queue_init() failed %i\n", ret); return T_EXIT_FAIL; } /* test that the creator iw allowed to submit */ ret = try_submit(&ring); if (ret) { fprintf(stderr, "the creator can't submit %i\n", ret); return T_EXIT_FAIL; } /* test that a second submitter doesn't succeed */ if (!fork_t()) { ret = try_submit(&ring); if (ret != -EEXIST) fprintf(stderr, "1: not owner child could submit %i\n", ret); return ret != -EEXIST; } wait_child_t(); io_uring_queue_exit(&ring); /* test that the first submitter but not creator can submit */ ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_R_DISABLED); if (ret) t_error(1, ret, "ring init (2) %i", ret); if (!fork_t()) { io_uring_enable_rings(&ring); ret = try_submit(&ring); if (ret) fprintf(stderr, "2: not owner child could submit %i\n", ret); return !!ret; } wait_child_t(); io_uring_queue_exit(&ring); /* test that only the first enabler can submit */ ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_R_DISABLED); if (ret) t_error(1, ret, "ring init (3) %i", ret); io_uring_enable_rings(&ring); if (!fork_t()) { ret = try_submit(&ring); if (ret != -EEXIST) fprintf(stderr, "3: not owner child could submit %i\n", ret); return ret != -EEXIST; } wait_child_t(); io_uring_queue_exit(&ring); /* test that anyone can submit to a SQPOLL|SINGLE_ISSUER ring */ ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_SQPOLL); if (ret) t_error(1, ret, "ring init (4) %i", ret); ret = try_submit(&ring); if (ret) { fprintf(stderr, "SQPOLL submit failed (creator) %i\n", ret); return T_EXIT_FAIL; } if (!fork_t()) { ret = try_submit(&ring); if (ret) fprintf(stderr, "SQPOLL submit failed (child) %i\n", ret); return !!ret; } wait_child_t(); io_uring_queue_exit(&ring); /* test that IORING_ENTER_REGISTERED_RING doesn't break anything */ ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER); if (ret) t_error(1, ret, "ring init (5) %i", ret); if (!fork_t()) { ret = try_submit(&ring); if (ret != -EEXIST) fprintf(stderr, "4: not owner child could submit %i\n", ret); return ret != -EEXIST; } wait_child_t(); io_uring_queue_exit(&ring); return T_EXIT_PASS; }