• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = &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