1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: run various nop tests
4 *
5 */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12
13 #include "liburing.h"
14 #include "test.h"
15
16 static int seq;
17
test_nop_inject(struct io_uring * ring,unsigned req_flags)18 static int test_nop_inject(struct io_uring *ring, unsigned req_flags)
19 {
20 struct io_uring_cqe *cqe;
21 struct io_uring_sqe *sqe;
22 int ret;
23
24 sqe = io_uring_get_sqe(ring);
25 if (!sqe) {
26 fprintf(stderr, "get sqe failed\n");
27 goto err;
28 }
29
30 io_uring_prep_nop(sqe);
31 sqe->user_data = ++seq;
32 sqe->nop_flags = IORING_NOP_INJECT_RESULT;
33 sqe->flags |= req_flags;
34 sqe->len = -EFAULT;
35
36 ret = io_uring_submit(ring);
37 if (ret <= 0) {
38 fprintf(stderr, "sqe submit failed: %d\n", ret);
39 goto err;
40 }
41
42 ret = io_uring_wait_cqe(ring, &cqe);
43 if (ret < 0) {
44 fprintf(stderr, "wait completion %d\n", ret);
45 goto err;
46 }
47 if (cqe->res != -EINVAL && cqe->res != -EFAULT) {
48 fprintf(stderr, "expected injected result, got %d\n", cqe->res);
49 goto err;
50 }
51 io_uring_cqe_seen(ring, cqe);
52 return 0;
53 err:
54 return 1;
55 }
56
test_single_nop(struct io_uring * ring,unsigned req_flags)57 static int test_single_nop(struct io_uring *ring, unsigned req_flags)
58 {
59 struct io_uring_cqe *cqe;
60 struct io_uring_sqe *sqe;
61 int ret;
62 bool cqe32 = (ring->flags & IORING_SETUP_CQE32);
63
64 sqe = io_uring_get_sqe(ring);
65 if (!sqe) {
66 fprintf(stderr, "get sqe failed\n");
67 goto err;
68 }
69
70 io_uring_prep_nop(sqe);
71 sqe->user_data = ++seq;
72 sqe->flags |= req_flags;
73
74 ret = io_uring_submit(ring);
75 if (ret <= 0) {
76 fprintf(stderr, "sqe submit failed: %d\n", ret);
77 goto err;
78 }
79
80 ret = io_uring_wait_cqe(ring, &cqe);
81 if (ret < 0) {
82 fprintf(stderr, "wait completion %d\n", ret);
83 goto err;
84 }
85 if (!cqe->user_data) {
86 fprintf(stderr, "Unexpected 0 user_data\n");
87 goto err;
88 }
89 if (cqe32) {
90 if (cqe->big_cqe[0] != 0) {
91 fprintf(stderr, "Unexpected extra1\n");
92 goto err;
93
94 }
95 if (cqe->big_cqe[1] != 0) {
96 fprintf(stderr, "Unexpected extra2\n");
97 goto err;
98 }
99 }
100 io_uring_cqe_seen(ring, cqe);
101 return 0;
102 err:
103 return 1;
104 }
105
test_barrier_nop(struct io_uring * ring,unsigned req_flags)106 static int test_barrier_nop(struct io_uring *ring, unsigned req_flags)
107 {
108 struct io_uring_cqe *cqe;
109 struct io_uring_sqe *sqe;
110 int ret, i;
111 bool cqe32 = (ring->flags & IORING_SETUP_CQE32);
112
113 for (i = 0; i < 8; i++) {
114 sqe = io_uring_get_sqe(ring);
115 if (!sqe) {
116 fprintf(stderr, "get sqe failed\n");
117 goto err;
118 }
119
120 io_uring_prep_nop(sqe);
121 if (i == 4)
122 sqe->flags = IOSQE_IO_DRAIN;
123 sqe->user_data = ++seq;
124 sqe->flags |= req_flags;
125 }
126
127 ret = io_uring_submit(ring);
128 if (ret < 0) {
129 fprintf(stderr, "sqe submit failed: %d\n", ret);
130 goto err;
131 } else if (ret < 8) {
132 fprintf(stderr, "Submitted only %d\n", ret);
133 goto err;
134 }
135
136 for (i = 0; i < 8; i++) {
137 ret = io_uring_wait_cqe(ring, &cqe);
138 if (ret < 0) {
139 fprintf(stderr, "wait completion %d\n", ret);
140 goto err;
141 }
142 if (!cqe->user_data) {
143 fprintf(stderr, "Unexpected 0 user_data\n");
144 goto err;
145 }
146 if (cqe32) {
147 if (cqe->big_cqe[0] != 0) {
148 fprintf(stderr, "Unexpected extra1\n");
149 goto err;
150 }
151 if (cqe->big_cqe[1] != 0) {
152 fprintf(stderr, "Unexpected extra2\n");
153 goto err;
154 }
155 }
156 io_uring_cqe_seen(ring, cqe);
157 }
158
159 return 0;
160 err:
161 return 1;
162 }
163
test_ring(unsigned flags)164 static int test_ring(unsigned flags)
165 {
166 struct io_uring ring;
167 struct io_uring_params p = { };
168 int ret, i;
169
170 p.flags = flags;
171 ret = io_uring_queue_init_params(8, &ring, &p);
172 if (ret) {
173 if (ret == -EINVAL)
174 return 0;
175 fprintf(stderr, "ring setup failed: %d\n", ret);
176 return 1;
177 }
178
179 for (i = 0; i < 1000; i++) {
180 unsigned req_flags = (i & 1) ? IOSQE_ASYNC : 0;
181
182 ret = test_single_nop(&ring, req_flags);
183 if (ret) {
184 fprintf(stderr, "test_single_nop failed\n");
185 goto err;
186 }
187
188 ret = test_barrier_nop(&ring, req_flags);
189 if (ret) {
190 fprintf(stderr, "test_barrier_nop failed\n");
191 goto err;
192 }
193 ret = test_nop_inject(&ring, req_flags);
194 if (ret) {
195 fprintf(stderr, "test_nop_inject failed\n");
196 goto err;
197 }
198 }
199 err:
200 io_uring_queue_exit(&ring);
201 return ret;
202 }
203
main(int argc,char * argv[])204 int main(int argc, char *argv[])
205 {
206 int ret;
207
208 if (argc > 1)
209 return 0;
210
211 FOR_ALL_TEST_CONFIGS {
212 ret = test_ring(IORING_GET_TEST_CONFIG_FLAGS());
213 if (ret) {
214 fprintf(stderr, "Normal ring test failed: %s\n",
215 IORING_GET_TEST_CONFIG_DESCRIPTION());
216 return ret;
217 }
218 }
219
220 return 0;
221 }
222