1 /* SPDX-License-Identifier: MIT */
2 #include <errno.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10
11 #include "liburing.h"
12 #include "test.h"
13 #include "helpers.h"
14
15 static pid_t pid;
16
fork_t(void)17 static pid_t fork_t(void)
18 {
19 pid = fork();
20 if (pid == -1) {
21 fprintf(stderr, "fork failed\n");
22 exit(T_EXIT_FAIL);
23 }
24 return pid;
25 }
26
wait_child_t(void)27 static void wait_child_t(void)
28 {
29 int wstatus;
30
31 if (waitpid(pid, &wstatus, 0) == (pid_t)-1) {
32 perror("waitpid()");
33 exit(T_EXIT_FAIL);
34 }
35 if (!WIFEXITED(wstatus)) {
36 fprintf(stderr, "child failed %i\n", WEXITSTATUS(wstatus));
37 exit(T_EXIT_FAIL);
38 }
39 if (WEXITSTATUS(wstatus))
40 exit(T_EXIT_FAIL);
41 }
42
try_submit(struct io_uring * ring)43 static int try_submit(struct io_uring *ring)
44 {
45 struct io_uring_cqe *cqe;
46 struct io_uring_sqe *sqe;
47 int ret;
48
49 sqe = io_uring_get_sqe(ring);
50 io_uring_prep_nop(sqe);
51 sqe->user_data = 42;
52
53 ret = io_uring_submit(ring);
54 if (ret < 0)
55 return ret;
56
57 if (ret != 1)
58 t_error(1, ret, "submit %i", ret);
59 ret = io_uring_wait_cqe(ring, &cqe);
60 if (ret)
61 t_error(1, ret, "wait fail %i", ret);
62
63 if (cqe->res || cqe->user_data != 42)
64 t_error(1, ret, "invalid cqe");
65
66 io_uring_cqe_seen(ring, cqe);
67 return 0;
68 }
69
main(int argc,char * argv[])70 int main(int argc, char *argv[])
71 {
72 struct io_uring ring;
73 int ret;
74
75 if (argc > 1)
76 return T_EXIT_SKIP;
77
78 ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER);
79 if (ret == -EINVAL) {
80 return T_EXIT_SKIP;
81 } else if (ret) {
82 fprintf(stderr, "io_uring_queue_init() failed %i\n", ret);
83 return T_EXIT_FAIL;
84 }
85
86 /* test that the creator iw allowed to submit */
87 ret = try_submit(&ring);
88 if (ret) {
89 fprintf(stderr, "the creator can't submit %i\n", ret);
90 return T_EXIT_FAIL;
91 }
92
93 /* test that a second submitter doesn't succeed */
94 if (!fork_t()) {
95 ret = try_submit(&ring);
96 if (ret != -EEXIST)
97 fprintf(stderr, "1: not owner child could submit %i\n", ret);
98 return ret != -EEXIST;
99 }
100 wait_child_t();
101 io_uring_queue_exit(&ring);
102
103 /* test that the first submitter but not creator can submit */
104 ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER |
105 IORING_SETUP_R_DISABLED);
106 if (ret)
107 t_error(1, ret, "ring init (2) %i", ret);
108
109 if (!fork_t()) {
110 io_uring_enable_rings(&ring);
111 ret = try_submit(&ring);
112 if (ret)
113 fprintf(stderr, "2: not owner child could submit %i\n", ret);
114 return !!ret;
115 }
116 wait_child_t();
117 io_uring_queue_exit(&ring);
118
119 /* test that only the first enabler can submit */
120 ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER |
121 IORING_SETUP_R_DISABLED);
122 if (ret)
123 t_error(1, ret, "ring init (3) %i", ret);
124
125 io_uring_enable_rings(&ring);
126 if (!fork_t()) {
127 ret = try_submit(&ring);
128 if (ret != -EEXIST)
129 fprintf(stderr, "3: not owner child could submit %i\n", ret);
130 return ret != -EEXIST;
131 }
132 wait_child_t();
133 io_uring_queue_exit(&ring);
134
135 /* test that anyone can submit to a SQPOLL|SINGLE_ISSUER ring */
136 ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_SQPOLL);
137 if (ret)
138 t_error(1, ret, "ring init (4) %i", ret);
139
140 ret = try_submit(&ring);
141 if (ret) {
142 fprintf(stderr, "SQPOLL submit failed (creator) %i\n", ret);
143 return T_EXIT_FAIL;
144 }
145
146 if (!fork_t()) {
147 ret = try_submit(&ring);
148 if (ret)
149 fprintf(stderr, "SQPOLL submit failed (child) %i\n", ret);
150 return !!ret;
151 }
152 wait_child_t();
153 io_uring_queue_exit(&ring);
154
155 /* test that IORING_ENTER_REGISTERED_RING doesn't break anything */
156 ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER);
157 if (ret)
158 t_error(1, ret, "ring init (5) %i", ret);
159
160 if (!fork_t()) {
161 ret = try_submit(&ring);
162 if (ret != -EEXIST)
163 fprintf(stderr, "4: not owner child could submit %i\n", ret);
164 return ret != -EEXIST;
165 }
166 wait_child_t();
167 io_uring_queue_exit(&ring);
168 return T_EXIT_PASS;
169 }
170