1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: test ring messaging command
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 #include <pthread.h>
13
14 #include "liburing.h"
15 #include "helpers.h"
16
17 static int no_msg;
18
test_own(struct io_uring * ring)19 static int test_own(struct io_uring *ring)
20 {
21 struct io_uring_cqe *cqe;
22 struct io_uring_sqe *sqe;
23 int ret, i;
24
25 sqe = io_uring_get_sqe(ring);
26 if (!sqe) {
27 fprintf(stderr, "get sqe failed\n");
28 goto err;
29 }
30
31 io_uring_prep_msg_ring(sqe, ring->ring_fd, 0x10, 0x1234, 0);
32 sqe->user_data = 1;
33
34 ret = io_uring_submit(ring);
35 if (ret <= 0) {
36 fprintf(stderr, "sqe submit failed: %d\n", ret);
37 goto err;
38 }
39
40 for (i = 0; i < 2; i++) {
41 ret = io_uring_wait_cqe(ring, &cqe);
42 if (ret < 0) {
43 fprintf(stderr, "wait completion %d\n", ret);
44 goto err;
45 }
46 switch (cqe->user_data) {
47 case 1:
48 if (cqe->res == -EINVAL || cqe->res == -EOPNOTSUPP) {
49 no_msg = 1;
50 return 0;
51 }
52 if (cqe->res != 0) {
53 fprintf(stderr, "cqe res %d\n", cqe->res);
54 return -1;
55 }
56 break;
57 case 0x1234:
58 if (cqe->res != 0x10) {
59 fprintf(stderr, "invalid len %x\n", cqe->res);
60 return -1;
61 }
62 break;
63 default:
64 fprintf(stderr, "Invalid user_data\n");
65 return -1;
66 }
67 io_uring_cqe_seen(ring, cqe);
68 }
69
70 return 0;
71 err:
72 return 1;
73 }
74
75 struct data {
76 struct io_uring *ring;
77 unsigned int flags;
78 pthread_barrier_t startup;
79 pthread_barrier_t barrier;
80 };
81
wait_cqe_fn(void * __data)82 static void *wait_cqe_fn(void *__data)
83 {
84 struct data *d = __data;
85 struct io_uring_cqe *cqe;
86 struct io_uring ring;
87 int ret;
88
89 io_uring_queue_init(4, &ring, d->flags);
90 d->ring = ˚
91 pthread_barrier_wait(&d->startup);
92
93 pthread_barrier_wait(&d->barrier);
94
95 ret = io_uring_wait_cqe(&ring, &cqe);
96 if (ret) {
97 fprintf(stderr, "wait cqe %d\n", ret);
98 goto err;
99 }
100
101 if (cqe->user_data != 0x5aa5) {
102 fprintf(stderr, "user_data %llx\n", (long long) cqe->user_data);
103 goto err;
104 }
105 if (cqe->res != 0x20) {
106 fprintf(stderr, "len %x\n", cqe->res);
107 goto err;
108 }
109
110 io_uring_cqe_seen(&ring, cqe);
111 io_uring_queue_exit(&ring);
112 return NULL;
113 err:
114 io_uring_cqe_seen(&ring, cqe);
115 io_uring_queue_exit(&ring);
116 return (void *) (unsigned long) 1;
117 }
118
test_remote(struct io_uring * ring,unsigned int ring_flags)119 static int test_remote(struct io_uring *ring, unsigned int ring_flags)
120 {
121 struct io_uring *target;
122 pthread_t thread;
123 void *tret;
124 struct io_uring_cqe *cqe;
125 struct io_uring_sqe *sqe;
126 struct data d;
127 int ret;
128
129 d.flags = ring_flags;
130 pthread_barrier_init(&d.barrier, NULL, 2);
131 pthread_barrier_init(&d.startup, NULL, 2);
132 pthread_create(&thread, NULL, wait_cqe_fn, &d);
133
134 pthread_barrier_wait(&d.startup);
135 target = d.ring;
136
137 sqe = io_uring_get_sqe(ring);
138 if (!sqe) {
139 fprintf(stderr, "get sqe failed\n");
140 goto err;
141 }
142
143 io_uring_prep_msg_ring(sqe, target->ring_fd, 0x20, 0x5aa5, 0);
144 sqe->user_data = 1;
145
146 ret = io_uring_submit(ring);
147 if (ret <= 0) {
148 fprintf(stderr, "sqe submit failed: %d\n", ret);
149 goto err;
150 }
151
152 pthread_barrier_wait(&d.barrier);
153
154 ret = io_uring_wait_cqe(ring, &cqe);
155 if (ret < 0) {
156 fprintf(stderr, "wait completion %d\n", ret);
157 goto err;
158 }
159 if (cqe->res != 0) {
160 fprintf(stderr, "cqe res %d\n", cqe->res);
161 io_uring_cqe_seen(ring, cqe);
162 return -1;
163 }
164 if (cqe->user_data != 1) {
165 fprintf(stderr, "user_data %llx\n", (long long) cqe->user_data);
166 io_uring_cqe_seen(ring, cqe);
167 return -1;
168 }
169
170 io_uring_cqe_seen(ring, cqe);
171 pthread_join(thread, &tret);
172 return 0;
173 err:
174 return 1;
175 }
176
remote_submit_fn(void * data)177 static void *remote_submit_fn(void *data)
178 {
179 struct io_uring_sqe *sqe;
180 struct io_uring_cqe *cqe;
181 struct io_uring *target = data;
182 struct io_uring ring;
183 int ret;
184
185 ret = io_uring_queue_init(8, &ring, 0);
186 if (ret) {
187 fprintf(stderr, "thread ring setup failed: %d\n", ret);
188 goto err;
189 }
190 sqe = io_uring_get_sqe(&ring);
191 if (!sqe) {
192 fprintf(stderr, "get sqe failed\n");
193 goto err;
194 }
195
196 io_uring_prep_msg_ring(sqe, target->ring_fd, 0x20, 0x5aa5, 0);
197 sqe->user_data = 1;
198
199 ret = io_uring_submit(&ring);
200 if (ret <= 0) {
201 fprintf(stderr, "sqe submit failed: %d\n", ret);
202 goto err;
203 }
204
205 ret = io_uring_wait_cqe(&ring, &cqe);
206 if (ret < 0) {
207 fprintf(stderr, "wait completion %d\n", ret);
208 goto err;
209 }
210 if (cqe->res != 0 || cqe->user_data != 1) {
211 fprintf(stderr, "invalid cqe\n");
212 goto err;
213 }
214 io_uring_cqe_seen(&ring, cqe);
215 io_uring_queue_exit(&ring);
216 return NULL;
217 err:
218 return (void *) (unsigned long) 1;
219 }
220
test_remote_submit(struct io_uring * target)221 static int test_remote_submit(struct io_uring *target)
222 {
223 struct io_uring_cqe *cqe;
224 pthread_t thread;
225 void *tret;
226 int ret;
227
228 pthread_create(&thread, NULL, remote_submit_fn, target);
229
230 ret = io_uring_wait_cqe(target, &cqe);
231 if (ret < 0) {
232 fprintf(stderr, "wait completion %d\n", ret);
233 goto err;
234 }
235 if (cqe->res != 0x20) {
236 fprintf(stderr, "cqe res %d\n", cqe->res);
237 return -1;
238 }
239 if (cqe->user_data != 0x5aa5) {
240 fprintf(stderr, "user_data %llx\n", (long long) cqe->user_data);
241 return -1;
242 }
243 io_uring_cqe_seen(target, cqe);
244 pthread_join(thread, &tret);
245 return 0;
246 err:
247 return 1;
248 }
249
test_invalid(struct io_uring * ring,bool fixed)250 static int test_invalid(struct io_uring *ring, bool fixed)
251 {
252 struct io_uring_cqe *cqe;
253 struct io_uring_sqe *sqe;
254 int ret, fd = 1;
255
256 sqe = io_uring_get_sqe(ring);
257 if (!sqe) {
258 fprintf(stderr, "get sqe failed\n");
259 return 1;
260 }
261
262 if (fixed) {
263 ret = io_uring_register_files(ring, &fd, 1);
264 if (ret) {
265 fprintf(stderr, "file register %d\n", ret);
266 return 1;
267 }
268 io_uring_prep_msg_ring(sqe, 0, 0, 0x8989, 0);
269 sqe->flags |= IOSQE_FIXED_FILE;
270 } else {
271 io_uring_prep_msg_ring(sqe, 1, 0, 0x8989, 0);
272 }
273
274 sqe->user_data = 1;
275
276 ret = io_uring_submit(ring);
277 if (ret <= 0) {
278 fprintf(stderr, "sqe submit failed: %d\n", ret);
279 goto err;
280 }
281
282 ret = io_uring_wait_cqe(ring, &cqe);
283 if (ret < 0) {
284 fprintf(stderr, "wait completion %d\n", ret);
285 goto err;
286 }
287 if (cqe->res != -EBADFD) {
288 fprintf(stderr, "cqe res %d\n", cqe->res);
289 return -1;
290 }
291
292 io_uring_cqe_seen(ring, cqe);
293 if (fixed)
294 io_uring_unregister_files(ring);
295 return 0;
296 err:
297 if (fixed)
298 io_uring_unregister_files(ring);
299 return 1;
300 }
301
test_disabled_ring(struct io_uring * ring,int flags)302 static int test_disabled_ring(struct io_uring *ring, int flags)
303 {
304 struct io_uring_cqe *cqe;
305 struct io_uring_sqe *sqe;
306 struct io_uring disabled_ring;
307 int ret;
308
309 flags |= IORING_SETUP_R_DISABLED;
310 ret = io_uring_queue_init(8, &disabled_ring, flags);
311 if (ret) {
312 fprintf(stderr, "ring setup failed: %d\n", ret);
313 return 1;
314 }
315
316 sqe = io_uring_get_sqe(ring);
317 io_uring_prep_msg_ring(sqe, disabled_ring.ring_fd, 0x10, 0x1234, 0);
318 sqe->user_data = 1;
319
320 ret = io_uring_submit(ring);
321 if (ret != 1) {
322 fprintf(stderr, "sqe submit failed: %d\n", ret);
323 return 1;
324 }
325
326 ret = io_uring_wait_cqe(ring, &cqe);
327 if (ret < 0) {
328 fprintf(stderr, "wait completion %d\n", ret);
329 return 1;
330 }
331 if (cqe->res != 0 && cqe->res != -EBADFD) {
332 fprintf(stderr, "cqe res %d\n", cqe->res);
333 return 1;
334 }
335 if (cqe->user_data != 1) {
336 fprintf(stderr, "user_data %llx\n", (long long) cqe->user_data);
337 return 1;
338 }
339
340 io_uring_cqe_seen(ring, cqe);
341 io_uring_queue_exit(&disabled_ring);
342 return 0;
343 }
344
test(int ring_flags)345 static int test(int ring_flags)
346 {
347 struct io_uring ring, ring2, pring;
348 int ret, i;
349
350 ret = io_uring_queue_init(8, &ring, ring_flags);
351 if (ret) {
352 fprintf(stderr, "ring setup failed: %d\n", ret);
353 return T_EXIT_FAIL;
354 }
355 ret = io_uring_queue_init(8, &ring2, ring_flags);
356 if (ret) {
357 fprintf(stderr, "ring setup failed: %d\n", ret);
358 return T_EXIT_FAIL;
359 }
360 ret = io_uring_queue_init(8, &pring, ring_flags | IORING_SETUP_IOPOLL);
361 if (ret) {
362 fprintf(stderr, "ring setup failed: %d\n", ret);
363 return T_EXIT_FAIL;
364 }
365
366 ret = test_own(&ring);
367 if (ret) {
368 fprintf(stderr, "test_own failed\n");
369 return T_EXIT_FAIL;
370 }
371 if (no_msg)
372 return T_EXIT_SKIP;
373 ret = test_own(&pring);
374 if (ret) {
375 fprintf(stderr, "test_own iopoll failed\n");
376 return T_EXIT_FAIL;
377 }
378
379 ret = test_invalid(&ring, 0);
380 if (ret) {
381 fprintf(stderr, "test_invalid failed\n");
382 return T_EXIT_FAIL;
383 }
384
385 for (i = 0; i < 2; i++) {
386 ret = test_invalid(&ring, 1);
387 if (ret) {
388 fprintf(stderr, "test_invalid fixed failed\n");
389 return T_EXIT_FAIL;
390 }
391 }
392
393 ret = test_remote(&ring, ring_flags);
394 if (ret) {
395 fprintf(stderr, "test_remote failed\n");
396 return T_EXIT_FAIL;
397 }
398
399 io_uring_queue_exit(&ring);
400 io_uring_queue_exit(&pring);
401
402 if (t_probe_defer_taskrun()) {
403 ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER |
404 IORING_SETUP_DEFER_TASKRUN);
405 if (ret) {
406 fprintf(stderr, "deferred ring setup failed: %d\n", ret);
407 return T_EXIT_FAIL;
408 }
409
410 ret = test_own(&ring);
411 if (ret) {
412 fprintf(stderr, "test_own deferred failed\n");
413 return T_EXIT_FAIL;
414 }
415
416 for (i = 0; i < 2; i++) {
417 ret = test_invalid(&ring, i);
418 if (ret) {
419 fprintf(stderr, "test_invalid(0) deferred failed\n");
420 return T_EXIT_FAIL;
421 }
422 }
423
424 ret = test_remote_submit(&ring);
425 if (ret) {
426 fprintf(stderr, "test_remote_submit failed\n");
427 return T_EXIT_FAIL;
428 }
429 io_uring_queue_exit(&ring);
430
431 if (test_disabled_ring(&ring2, 0)) {
432 fprintf(stderr, "test_disabled_ring failed\n");
433 return T_EXIT_FAIL;
434 }
435
436 if (test_disabled_ring(&ring2, IORING_SETUP_SINGLE_ISSUER |
437 IORING_SETUP_DEFER_TASKRUN)) {
438 fprintf(stderr, "test_disabled_ring defer failed\n");
439 return T_EXIT_FAIL;
440 }
441 }
442
443 io_uring_queue_exit(&ring2);
444 return T_EXIT_PASS;
445 }
446
main(int argc,char * argv[])447 int main(int argc, char *argv[])
448 {
449 int ret;
450
451 if (argc > 1)
452 return T_EXIT_SKIP;
453
454 ret = test(0);
455 if (ret != T_EXIT_PASS) {
456 fprintf(stderr, "ring flags 0 failed\n");
457 return ret;
458 }
459
460 ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN);
461 if (ret != T_EXIT_PASS) {
462 fprintf(stderr, "ring flags defer failed\n");
463 return ret;
464 }
465
466 return ret;
467 }
468