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