xref: /aosp_15_r20/external/liburing/test/link.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: run various linked sqe 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 
15 static int no_hardlink;
16 
17 /*
18  * Timer with single nop
19  */
test_single_hardlink(struct io_uring * ring)20 static int test_single_hardlink(struct io_uring *ring)
21 {
22 	struct __kernel_timespec ts;
23 	struct io_uring_cqe *cqe;
24 	struct io_uring_sqe *sqe;
25 	int ret, i;
26 
27 	sqe = io_uring_get_sqe(ring);
28 	if (!sqe) {
29 		fprintf(stderr, "get sqe failed\n");
30 		goto err;
31 	}
32 	ts.tv_sec = 0;
33 	ts.tv_nsec = 10000000ULL;
34 	io_uring_prep_timeout(sqe, &ts, 0, 0);
35 	sqe->flags |= IOSQE_IO_LINK | IOSQE_IO_HARDLINK;
36 	sqe->user_data = 1;
37 
38 	sqe = io_uring_get_sqe(ring);
39 	if (!sqe) {
40 		fprintf(stderr, "get sqe failed\n");
41 		goto err;
42 	}
43 	io_uring_prep_nop(sqe);
44 	sqe->user_data = 2;
45 
46 	ret = io_uring_submit(ring);
47 	if (ret <= 0) {
48 		fprintf(stderr, "sqe submit failed: %d\n", ret);
49 		goto err;
50 	}
51 
52 	for (i = 0; i < 2; i++) {
53 		ret = io_uring_wait_cqe(ring, &cqe);
54 		if (ret < 0) {
55 			fprintf(stderr, "wait completion %d\n", ret);
56 			goto err;
57 		}
58 		if (!cqe) {
59 			fprintf(stderr, "failed to get cqe\n");
60 			goto err;
61 		}
62 		if (no_hardlink)
63 			goto next;
64 		if (cqe->user_data == 1 && cqe->res == -EINVAL) {
65 			fprintf(stdout, "Hard links not supported, skipping\n");
66 			no_hardlink = 1;
67 			goto next;
68 		}
69 		if (cqe->user_data == 1 && cqe->res != -ETIME) {
70 			fprintf(stderr, "timeout failed with %d\n", cqe->res);
71 			goto err;
72 		}
73 		if (cqe->user_data == 2 && cqe->res) {
74 			fprintf(stderr, "nop failed with %d\n", cqe->res);
75 			goto err;
76 		}
77 next:
78 		io_uring_cqe_seen(ring, cqe);
79 	}
80 
81 	return 0;
82 err:
83 	return 1;
84 }
85 
86 /*
87  * Timer -> timer -> nop
88  */
test_double_hardlink(struct io_uring * ring)89 static int test_double_hardlink(struct io_uring *ring)
90 {
91 	struct __kernel_timespec ts1, ts2;
92 	struct io_uring_cqe *cqe;
93 	struct io_uring_sqe *sqe;
94 	int ret, i;
95 
96 	if (no_hardlink)
97 		return 0;
98 
99 	sqe = io_uring_get_sqe(ring);
100 	if (!sqe) {
101 		fprintf(stderr, "get sqe failed\n");
102 		goto err;
103 	}
104 	ts1.tv_sec = 0;
105 	ts1.tv_nsec = 10000000ULL;
106 	io_uring_prep_timeout(sqe, &ts1, 0, 0);
107 	sqe->flags |= IOSQE_IO_LINK | IOSQE_IO_HARDLINK;
108 	sqe->user_data = 1;
109 
110 	sqe = io_uring_get_sqe(ring);
111 	if (!sqe) {
112 		fprintf(stderr, "get sqe failed\n");
113 		goto err;
114 	}
115 	ts2.tv_sec = 0;
116 	ts2.tv_nsec = 15000000ULL;
117 	io_uring_prep_timeout(sqe, &ts2, 0, 0);
118 	sqe->flags |= IOSQE_IO_LINK | IOSQE_IO_HARDLINK;
119 	sqe->user_data = 2;
120 
121 	sqe = io_uring_get_sqe(ring);
122 	if (!sqe) {
123 		fprintf(stderr, "get sqe failed\n");
124 		goto err;
125 	}
126 	io_uring_prep_nop(sqe);
127 	sqe->user_data = 3;
128 
129 	ret = io_uring_submit(ring);
130 	if (ret <= 0) {
131 		fprintf(stderr, "sqe submit failed: %d\n", ret);
132 		goto err;
133 	}
134 
135 	for (i = 0; i < 3; i++) {
136 		ret = io_uring_wait_cqe(ring, &cqe);
137 		if (ret < 0) {
138 			fprintf(stderr, "wait completion %d\n", ret);
139 			goto err;
140 		}
141 		if (!cqe) {
142 			fprintf(stderr, "failed to get cqe\n");
143 			goto err;
144 		}
145 		if (cqe->user_data == 1 && cqe->res != -ETIME) {
146 			fprintf(stderr, "timeout failed with %d\n", cqe->res);
147 			goto err;
148 		}
149 		if (cqe->user_data == 2 && cqe->res != -ETIME) {
150 			fprintf(stderr, "timeout failed with %d\n", cqe->res);
151 			goto err;
152 		}
153 		if (cqe->user_data == 3 && cqe->res) {
154 			fprintf(stderr, "nop failed with %d\n", cqe->res);
155 			goto err;
156 		}
157 		io_uring_cqe_seen(ring, cqe);
158 	}
159 
160 	return 0;
161 err:
162 	return 1;
163 
164 }
165 
166 /*
167  * Test failing head of chain, and dependent getting -ECANCELED
168  */
test_single_link_fail(struct io_uring * ring)169 static int test_single_link_fail(struct io_uring *ring)
170 {
171 	struct io_uring_cqe *cqe;
172 	struct io_uring_sqe *sqe;
173 	int ret, i;
174 
175 	sqe = io_uring_get_sqe(ring);
176 	if (!sqe) {
177 		printf("get sqe failed\n");
178 		goto err;
179 	}
180 
181 	io_uring_prep_remove_buffers(sqe, 10, 1);
182 	sqe->flags |= IOSQE_IO_LINK;
183 
184 	sqe = io_uring_get_sqe(ring);
185 	if (!sqe) {
186 		printf("get sqe failed\n");
187 		goto err;
188 	}
189 
190 	io_uring_prep_nop(sqe);
191 
192 	ret = io_uring_submit(ring);
193 	if (ret <= 0) {
194 		printf("sqe submit failed: %d\n", ret);
195 		goto err;
196 	}
197 
198 	for (i = 0; i < 2; i++) {
199 		ret = io_uring_peek_cqe(ring, &cqe);
200 		if (ret < 0) {
201 			printf("wait completion %d\n", ret);
202 			goto err;
203 		}
204 		if (!cqe) {
205 			printf("failed to get cqe\n");
206 			goto err;
207 		}
208 		if (i == 0 && cqe->res != -ENOENT) {
209 			printf("sqe0 failed with %d, wanted -ENOENT\n", cqe->res);
210 			goto err;
211 		}
212 		if (i == 1 && cqe->res != -ECANCELED) {
213 			printf("sqe1 failed with %d, wanted -ECANCELED\n", cqe->res);
214 			goto err;
215 		}
216 		io_uring_cqe_seen(ring, cqe);
217 	}
218 
219 	return 0;
220 err:
221 	return 1;
222 }
223 
224 /*
225  * Test two independent chains
226  */
test_double_chain(struct io_uring * ring)227 static int test_double_chain(struct io_uring *ring)
228 {
229 	struct io_uring_cqe *cqe;
230 	struct io_uring_sqe *sqe;
231 	int ret, i;
232 
233 	sqe = io_uring_get_sqe(ring);
234 	if (!sqe) {
235 		printf("get sqe failed\n");
236 		goto err;
237 	}
238 
239 	io_uring_prep_nop(sqe);
240 	sqe->flags |= IOSQE_IO_LINK;
241 
242 	sqe = io_uring_get_sqe(ring);
243 	if (!sqe) {
244 		printf("get sqe failed\n");
245 		goto err;
246 	}
247 
248 	io_uring_prep_nop(sqe);
249 
250 	sqe = io_uring_get_sqe(ring);
251 	if (!sqe) {
252 		printf("get sqe failed\n");
253 		goto err;
254 	}
255 
256 	io_uring_prep_nop(sqe);
257 	sqe->flags |= IOSQE_IO_LINK;
258 
259 	sqe = io_uring_get_sqe(ring);
260 	if (!sqe) {
261 		printf("get sqe failed\n");
262 		goto err;
263 	}
264 
265 	io_uring_prep_nop(sqe);
266 
267 	ret = io_uring_submit(ring);
268 	if (ret <= 0) {
269 		printf("sqe submit failed: %d\n", ret);
270 		goto err;
271 	}
272 
273 	for (i = 0; i < 4; i++) {
274 		ret = io_uring_wait_cqe(ring, &cqe);
275 		if (ret < 0) {
276 			printf("wait completion %d\n", ret);
277 			goto err;
278 		}
279 		io_uring_cqe_seen(ring, cqe);
280 	}
281 
282 	return 0;
283 err:
284 	return 1;
285 }
286 
287 /*
288  * Test multiple dependents
289  */
test_double_link(struct io_uring * ring)290 static int test_double_link(struct io_uring *ring)
291 {
292 	struct io_uring_cqe *cqe;
293 	struct io_uring_sqe *sqe;
294 	int ret, i;
295 
296 	sqe = io_uring_get_sqe(ring);
297 	if (!sqe) {
298 		printf("get sqe failed\n");
299 		goto err;
300 	}
301 
302 	io_uring_prep_nop(sqe);
303 	sqe->flags |= IOSQE_IO_LINK;
304 
305 	sqe = io_uring_get_sqe(ring);
306 	if (!sqe) {
307 		printf("get sqe failed\n");
308 		goto err;
309 	}
310 
311 	io_uring_prep_nop(sqe);
312 	sqe->flags |= IOSQE_IO_LINK;
313 
314 	sqe = io_uring_get_sqe(ring);
315 	if (!sqe) {
316 		printf("get sqe failed\n");
317 		goto err;
318 	}
319 
320 	io_uring_prep_nop(sqe);
321 
322 	ret = io_uring_submit(ring);
323 	if (ret <= 0) {
324 		printf("sqe submit failed: %d\n", ret);
325 		goto err;
326 	}
327 
328 	for (i = 0; i < 3; i++) {
329 		ret = io_uring_wait_cqe(ring, &cqe);
330 		if (ret < 0) {
331 			printf("wait completion %d\n", ret);
332 			goto err;
333 		}
334 		io_uring_cqe_seen(ring, cqe);
335 	}
336 
337 	return 0;
338 err:
339 	return 1;
340 }
341 
342 /*
343  * Test single dependency
344  */
test_single_link(struct io_uring * ring)345 static int test_single_link(struct io_uring *ring)
346 {
347 	struct io_uring_cqe *cqe;
348 	struct io_uring_sqe *sqe;
349 	int ret, i;
350 
351 	sqe = io_uring_get_sqe(ring);
352 	if (!sqe) {
353 		printf("get sqe failed\n");
354 		goto err;
355 	}
356 
357 	io_uring_prep_nop(sqe);
358 	sqe->flags |= IOSQE_IO_LINK;
359 
360 	sqe = io_uring_get_sqe(ring);
361 	if (!sqe) {
362 		printf("get sqe failed\n");
363 		goto err;
364 	}
365 
366 	io_uring_prep_nop(sqe);
367 
368 	ret = io_uring_submit(ring);
369 	if (ret <= 0) {
370 		printf("sqe submit failed: %d\n", ret);
371 		goto err;
372 	}
373 
374 	for (i = 0; i < 2; i++) {
375 		ret = io_uring_wait_cqe(ring, &cqe);
376 		if (ret < 0) {
377 			printf("wait completion %d\n", ret);
378 			goto err;
379 		}
380 		io_uring_cqe_seen(ring, cqe);
381 	}
382 
383 	return 0;
384 err:
385 	return 1;
386 }
387 
test_early_fail_and_wait(void)388 static int test_early_fail_and_wait(void)
389 {
390 	struct io_uring ring;
391 	struct io_uring_sqe *sqe;
392 	int ret, invalid_fd = 42;
393 	struct iovec iov = { .iov_base = NULL, .iov_len = 0 };
394 
395 	/* create a new ring as it leaves it dirty */
396 	ret = io_uring_queue_init(8, &ring, 0);
397 	if (ret) {
398 		printf("ring setup failed\n");
399 		return 1;
400 	}
401 
402 	sqe = io_uring_get_sqe(&ring);
403 	if (!sqe) {
404 		printf("get sqe failed\n");
405 		goto err;
406 	}
407 
408 	io_uring_prep_readv(sqe, invalid_fd, &iov, 1, 0);
409 	sqe->flags |= IOSQE_IO_LINK;
410 
411 	sqe = io_uring_get_sqe(&ring);
412 	if (!sqe) {
413 		printf("get sqe failed\n");
414 		goto err;
415 	}
416 
417 	io_uring_prep_nop(sqe);
418 
419 	ret = io_uring_submit_and_wait(&ring, 2);
420 	if (ret <= 0 && ret != -EAGAIN) {
421 		printf("sqe submit failed: %d\n", ret);
422 		goto err;
423 	}
424 
425 	io_uring_queue_exit(&ring);
426 	return 0;
427 err:
428 	io_uring_queue_exit(&ring);
429 	return 1;
430 }
431 
main(int argc,char * argv[])432 int main(int argc, char *argv[])
433 {
434 	struct io_uring ring, poll_ring;
435 	int ret;
436 
437 	if (argc > 1)
438 		return 0;
439 
440 	ret = io_uring_queue_init(8, &ring, 0);
441 	if (ret) {
442 		printf("ring setup failed\n");
443 		return 1;
444 
445 	}
446 
447 	ret = io_uring_queue_init(8, &poll_ring, IORING_SETUP_IOPOLL);
448 	if (ret) {
449 		printf("poll_ring setup failed\n");
450 		return 1;
451 	}
452 
453 	ret = test_single_link(&ring);
454 	if (ret) {
455 		printf("test_single_link failed\n");
456 		return ret;
457 	}
458 
459 	ret = test_double_link(&ring);
460 	if (ret) {
461 		printf("test_double_link failed\n");
462 		return ret;
463 	}
464 
465 	ret = test_double_chain(&ring);
466 	if (ret) {
467 		printf("test_double_chain failed\n");
468 		return ret;
469 	}
470 
471 	ret = test_single_link_fail(&poll_ring);
472 	if (ret) {
473 		printf("test_single_link_fail failed\n");
474 		return ret;
475 	}
476 
477 	ret = test_single_hardlink(&ring);
478 	if (ret) {
479 		fprintf(stderr, "test_single_hardlink\n");
480 		return ret;
481 	}
482 
483 	ret = test_double_hardlink(&ring);
484 	if (ret) {
485 		fprintf(stderr, "test_double_hardlink\n");
486 		return ret;
487 	}
488 
489 	ret = test_early_fail_and_wait();
490 	if (ret) {
491 		fprintf(stderr, "test_early_fail_and_wait\n");
492 		return ret;
493 	}
494 
495 	return 0;
496 }
497