• 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 		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