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 if (ret == -EINVAL)
313 return T_EXIT_SKIP;
314 fprintf(stderr, "ring setup failed: %d\n", ret);
315 return 1;
316 }
317
318 sqe = io_uring_get_sqe(ring);
319 io_uring_prep_msg_ring(sqe, disabled_ring.ring_fd, 0x10, 0x1234, 0);
320 sqe->user_data = 1;
321
322 ret = io_uring_submit(ring);
323 if (ret != 1) {
324 fprintf(stderr, "sqe submit failed: %d\n", ret);
325 return 1;
326 }
327
328 ret = io_uring_wait_cqe(ring, &cqe);
329 if (ret < 0) {
330 fprintf(stderr, "wait completion %d\n", ret);
331 return 1;
332 }
333 if (cqe->res != 0 && cqe->res != -EBADFD) {
334 fprintf(stderr, "cqe res %d\n", cqe->res);
335 return 1;
336 }
337 if (cqe->user_data != 1) {
338 fprintf(stderr, "user_data %llx\n", (long long) cqe->user_data);
339 return 1;
340 }
341
342 io_uring_cqe_seen(ring, cqe);
343 io_uring_queue_exit(&disabled_ring);
344 return 0;
345 }
346
test(int ring_flags)347 static int test(int ring_flags)
348 {
349 struct io_uring ring, ring2, pring;
350 int ret, i;
351
352 ret = io_uring_queue_init(8, &ring, ring_flags);
353 if (ret) {
354 if (ret == -EINVAL)
355 return T_EXIT_SKIP;
356 fprintf(stderr, "ring setup failed: %d\n", ret);
357 return T_EXIT_FAIL;
358 }
359 ret = io_uring_queue_init(8, &ring2, ring_flags);
360 if (ret) {
361 fprintf(stderr, "ring setup failed: %d\n", ret);
362 return T_EXIT_FAIL;
363 }
364 ret = io_uring_queue_init(8, &pring, ring_flags | IORING_SETUP_IOPOLL);
365 if (ret) {
366 fprintf(stderr, "ring setup failed: %d\n", ret);
367 return T_EXIT_FAIL;
368 }
369
370 ret = test_own(&ring);
371 if (ret) {
372 fprintf(stderr, "test_own failed\n");
373 return T_EXIT_FAIL;
374 }
375 if (no_msg)
376 return T_EXIT_SKIP;
377 ret = test_own(&pring);
378 if (ret) {
379 fprintf(stderr, "test_own iopoll failed\n");
380 return T_EXIT_FAIL;
381 }
382
383 ret = test_invalid(&ring, 0);
384 if (ret) {
385 fprintf(stderr, "test_invalid failed\n");
386 return T_EXIT_FAIL;
387 }
388
389 for (i = 0; i < 2; i++) {
390 ret = test_invalid(&ring, 1);
391 if (ret) {
392 fprintf(stderr, "test_invalid fixed failed\n");
393 return T_EXIT_FAIL;
394 }
395 }
396
397 ret = test_remote(&ring, ring_flags);
398 if (ret) {
399 fprintf(stderr, "test_remote failed\n");
400 return T_EXIT_FAIL;
401 }
402
403 io_uring_queue_exit(&ring);
404 io_uring_queue_exit(&pring);
405
406 if (t_probe_defer_taskrun()) {
407 ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER |
408 IORING_SETUP_DEFER_TASKRUN);
409 if (ret) {
410 fprintf(stderr, "deferred ring setup failed: %d\n", ret);
411 return T_EXIT_FAIL;
412 }
413
414 ret = test_own(&ring);
415 if (ret) {
416 fprintf(stderr, "test_own deferred failed\n");
417 return T_EXIT_FAIL;
418 }
419
420 for (i = 0; i < 2; i++) {
421 ret = test_invalid(&ring, i);
422 if (ret) {
423 fprintf(stderr, "test_invalid(0) deferred failed\n");
424 return T_EXIT_FAIL;
425 }
426 }
427
428 ret = test_remote_submit(&ring);
429 if (ret) {
430 fprintf(stderr, "test_remote_submit failed\n");
431 return T_EXIT_FAIL;
432 }
433 io_uring_queue_exit(&ring);
434
435 if (test_disabled_ring(&ring2, 0)) {
436 fprintf(stderr, "test_disabled_ring failed\n");
437 return T_EXIT_FAIL;
438 }
439
440 if (test_disabled_ring(&ring2, IORING_SETUP_SINGLE_ISSUER |
441 IORING_SETUP_DEFER_TASKRUN)) {
442 fprintf(stderr, "test_disabled_ring defer failed\n");
443 return T_EXIT_FAIL;
444 }
445 }
446
447 io_uring_queue_exit(&ring2);
448 return T_EXIT_PASS;
449 }
450
main(int argc,char * argv[])451 int main(int argc, char *argv[])
452 {
453 int ret;
454
455 if (argc > 1)
456 return T_EXIT_SKIP;
457
458 ret = test(0);
459 if (ret == T_EXIT_FAIL) {
460 fprintf(stderr, "ring flags 0 failed\n");
461 return ret;
462 } else if (ret == T_EXIT_SKIP) {
463 return T_EXIT_SKIP;
464 }
465
466 ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN);
467 if (ret == T_EXIT_FAIL) {
468 fprintf(stderr, "ring flags defer failed\n");
469 return ret;
470 }
471
472 return ret;
473 }
474