• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: basic read/write tests with buffered, O_DIRECT, and SQPOLL
4  */
5 #include <errno.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <fcntl.h>
11 #include <sys/types.h>
12 #include <sys/poll.h>
13 #include <sys/eventfd.h>
14 #include <sys/resource.h>
15 
16 #include "helpers.h"
17 #include "liburing.h"
18 
19 #define FILE_SIZE	(128 * 1024)
20 #define BS		4096
21 #define BUFFERS		(FILE_SIZE / BS)
22 
23 static struct iovec *vecs;
24 static int no_read;
25 static int no_buf_select;
26 static int warned;
27 
create_nonaligned_buffers(void)28 static int create_nonaligned_buffers(void)
29 {
30 	int i;
31 
32 	vecs = t_malloc(BUFFERS * sizeof(struct iovec));
33 	for (i = 0; i < BUFFERS; i++) {
34 		char *p = t_malloc(3 * BS);
35 
36 		if (!p)
37 			return 1;
38 		vecs[i].iov_base = p + (rand() % BS);
39 		vecs[i].iov_len = 1 + (rand() % BS);
40 	}
41 
42 	return 0;
43 }
44 
__test_io(const char * file,struct io_uring * ring,int write,int buffered,int sqthread,int fixed,int nonvec,int buf_select,int seq,int exp_len)45 static int __test_io(const char *file, struct io_uring *ring, int write,
46 		     int buffered, int sqthread, int fixed, int nonvec,
47 		     int buf_select, int seq, int exp_len)
48 {
49 	struct io_uring_sqe *sqe;
50 	struct io_uring_cqe *cqe;
51 	int open_flags;
52 	int i, fd, ret;
53 	off_t offset;
54 
55 #ifdef VERBOSE
56 	fprintf(stdout, "%s: start %d/%d/%d/%d/%d: ", __FUNCTION__, write,
57 							buffered, sqthread,
58 							fixed, nonvec);
59 #endif
60 	if (sqthread && geteuid()) {
61 #ifdef VERBOSE
62 		fprintf(stdout, "SKIPPED (not root)\n");
63 #endif
64 		return 0;
65 	}
66 
67 	if (write)
68 		open_flags = O_WRONLY;
69 	else
70 		open_flags = O_RDONLY;
71 	if (!buffered)
72 		open_flags |= O_DIRECT;
73 
74 	fd = open(file, open_flags);
75 	if (fd < 0) {
76 		perror("file open");
77 		goto err;
78 	}
79 
80 	if (fixed) {
81 		ret = io_uring_register_buffers(ring, vecs, BUFFERS);
82 		if (ret) {
83 			fprintf(stderr, "buffer reg failed: %d\n", ret);
84 			goto err;
85 		}
86 	}
87 	if (sqthread) {
88 		ret = io_uring_register_files(ring, &fd, 1);
89 		if (ret) {
90 			fprintf(stderr, "file reg failed: %d\n", ret);
91 			goto err;
92 		}
93 	}
94 
95 	offset = 0;
96 	for (i = 0; i < BUFFERS; i++) {
97 		sqe = io_uring_get_sqe(ring);
98 		if (!sqe) {
99 			fprintf(stderr, "sqe get failed\n");
100 			goto err;
101 		}
102 		if (!seq)
103 			offset = BS * (rand() % BUFFERS);
104 		if (write) {
105 			int do_fixed = fixed;
106 			int use_fd = fd;
107 
108 			if (sqthread)
109 				use_fd = 0;
110 			if (fixed && (i & 1))
111 				do_fixed = 0;
112 			if (do_fixed) {
113 				io_uring_prep_write_fixed(sqe, use_fd, vecs[i].iov_base,
114 								vecs[i].iov_len,
115 								offset, i);
116 			} else if (nonvec) {
117 				io_uring_prep_write(sqe, use_fd, vecs[i].iov_base,
118 							vecs[i].iov_len, offset);
119 			} else {
120 				io_uring_prep_writev(sqe, use_fd, &vecs[i], 1,
121 								offset);
122 			}
123 		} else {
124 			int do_fixed = fixed;
125 			int use_fd = fd;
126 
127 			if (sqthread)
128 				use_fd = 0;
129 			if (fixed && (i & 1))
130 				do_fixed = 0;
131 			if (do_fixed) {
132 				io_uring_prep_read_fixed(sqe, use_fd, vecs[i].iov_base,
133 								vecs[i].iov_len,
134 								offset, i);
135 			} else if (nonvec) {
136 				io_uring_prep_read(sqe, use_fd, vecs[i].iov_base,
137 							vecs[i].iov_len, offset);
138 			} else {
139 				io_uring_prep_readv(sqe, use_fd, &vecs[i], 1,
140 								offset);
141 			}
142 
143 		}
144 		sqe->user_data = i;
145 		if (sqthread)
146 			sqe->flags |= IOSQE_FIXED_FILE;
147 		if (buf_select) {
148 			if (nonvec)
149 				sqe->addr = 0;
150 			sqe->flags |= IOSQE_BUFFER_SELECT;
151 			sqe->buf_group = buf_select;
152 		}
153 		if (seq)
154 			offset += BS;
155 	}
156 
157 	ret = io_uring_submit(ring);
158 	if (ret != BUFFERS) {
159 		fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
160 		goto err;
161 	}
162 
163 	for (i = 0; i < BUFFERS; i++) {
164 		ret = io_uring_wait_cqe(ring, &cqe);
165 		if (ret) {
166 			fprintf(stderr, "wait_cqe=%d\n", ret);
167 			goto err;
168 		}
169 		if (cqe->res == -EINVAL && nonvec) {
170 			if (!warned) {
171 				fprintf(stdout, "Non-vectored IO not "
172 					"supported, skipping\n");
173 				warned = 1;
174 				no_read = 1;
175 			}
176 		} else if (exp_len == -1) {
177 			int iov_len = vecs[cqe->user_data].iov_len;
178 
179 			if (cqe->res != iov_len) {
180 				fprintf(stderr, "cqe res %d, wanted %d\n",
181 					cqe->res, iov_len);
182 				goto err;
183 			}
184 		} else if (cqe->res != exp_len) {
185 			fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res, exp_len);
186 			goto err;
187 		}
188 		if (buf_select && exp_len == BS) {
189 			int bid = cqe->flags >> 16;
190 			unsigned char *ptr = vecs[bid].iov_base;
191 			int j;
192 
193 			for (j = 0; j < BS; j++) {
194 				if (ptr[j] == cqe->user_data)
195 					continue;
196 
197 				fprintf(stderr, "Data mismatch! bid=%d, "
198 						"wanted=%d, got=%d\n", bid,
199 						(int)cqe->user_data, ptr[j]);
200 				return 1;
201 			}
202 		}
203 		io_uring_cqe_seen(ring, cqe);
204 	}
205 
206 	if (fixed) {
207 		ret = io_uring_unregister_buffers(ring);
208 		if (ret) {
209 			fprintf(stderr, "buffer unreg failed: %d\n", ret);
210 			goto err;
211 		}
212 	}
213 	if (sqthread) {
214 		ret = io_uring_unregister_files(ring);
215 		if (ret) {
216 			fprintf(stderr, "file unreg failed: %d\n", ret);
217 			goto err;
218 		}
219 	}
220 
221 	close(fd);
222 #ifdef VERBOSE
223 	fprintf(stdout, "PASS\n");
224 #endif
225 	return 0;
226 err:
227 #ifdef VERBOSE
228 	fprintf(stderr, "FAILED\n");
229 #endif
230 	if (fd != -1)
231 		close(fd);
232 	return 1;
233 }
test_io(const char * file,int write,int buffered,int sqthread,int fixed,int nonvec,int exp_len)234 static int test_io(const char *file, int write, int buffered, int sqthread,
235 		   int fixed, int nonvec, int exp_len)
236 {
237 	struct io_uring ring;
238 	int ret, ring_flags;
239 
240 	if (sqthread) {
241 		if (geteuid()) {
242 			if (!warned) {
243 				fprintf(stderr, "SQPOLL requires root, skipping\n");
244 				warned = 1;
245 			}
246 			return 0;
247 		}
248 		ring_flags = IORING_SETUP_SQPOLL;
249 	} else {
250 		ring_flags = 0;
251 	}
252 
253 	ret = io_uring_queue_init(64, &ring, ring_flags);
254 	if (ret) {
255 		fprintf(stderr, "ring create failed: %d\n", ret);
256 		return 1;
257 	}
258 
259 	ret = __test_io(file, &ring, write, buffered, sqthread, fixed, nonvec,
260 			0, 0, exp_len);
261 
262 	io_uring_queue_exit(&ring);
263 	return ret;
264 }
265 
read_poll_link(const char * file)266 static int read_poll_link(const char *file)
267 {
268 	struct __kernel_timespec ts;
269 	struct io_uring_sqe *sqe;
270 	struct io_uring_cqe *cqe;
271 	struct io_uring ring;
272 	int i, fd, ret, fds[2];
273 
274 	ret = io_uring_queue_init(8, &ring, 0);
275 	if (ret)
276 		return ret;
277 
278 	fd = open(file, O_WRONLY);
279 	if (fd < 0) {
280 		perror("open");
281 		return 1;
282 	}
283 
284 	if (pipe(fds)) {
285 		perror("pipe");
286 		return 1;
287 	}
288 
289 	sqe = io_uring_get_sqe(&ring);
290 	io_uring_prep_writev(sqe, fd, &vecs[0], 1, 0);
291 	sqe->flags |= IOSQE_IO_LINK;
292 	sqe->user_data = 1;
293 
294 	sqe = io_uring_get_sqe(&ring);
295 	io_uring_prep_poll_add(sqe, fds[0], POLLIN);
296 	sqe->flags |= IOSQE_IO_LINK;
297 	sqe->user_data = 2;
298 
299 	ts.tv_sec = 1;
300 	ts.tv_nsec = 0;
301 	sqe = io_uring_get_sqe(&ring);
302 	io_uring_prep_link_timeout(sqe, &ts, 0);
303 	sqe->user_data = 3;
304 
305 	ret = io_uring_submit(&ring);
306 	if (ret != 3) {
307 		fprintf(stderr, "submitted %d\n", ret);
308 		return 1;
309 	}
310 
311 	for (i = 0; i < 3; i++) {
312 		ret = io_uring_wait_cqe(&ring, &cqe);
313 		if (ret) {
314 			fprintf(stderr, "wait_cqe=%d\n", ret);
315 			return 1;
316 		}
317 		io_uring_cqe_seen(&ring, cqe);
318 	}
319 
320 	return 0;
321 }
322 
has_nonvec_read(void)323 static int has_nonvec_read(void)
324 {
325 	struct io_uring_probe *p;
326 	struct io_uring ring;
327 	int ret;
328 
329 	ret = io_uring_queue_init(1, &ring, 0);
330 	if (ret) {
331 		fprintf(stderr, "queue init failed: %d\n", ret);
332 		exit(ret);
333 	}
334 
335 	p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op));
336 	ret = io_uring_register_probe(&ring, p, 256);
337 	/* if we don't have PROBE_REGISTER, we don't have OP_READ/WRITE */
338 	if (ret == -EINVAL) {
339 out:
340 		io_uring_queue_exit(&ring);
341 		return 0;
342 	} else if (ret) {
343 		fprintf(stderr, "register_probe: %d\n", ret);
344 		goto out;
345 	}
346 
347 	if (p->ops_len <= IORING_OP_READ)
348 		goto out;
349 	if (!(p->ops[IORING_OP_READ].flags & IO_URING_OP_SUPPORTED))
350 		goto out;
351 	io_uring_queue_exit(&ring);
352 	return 1;
353 }
354 
test_eventfd_read(void)355 static int test_eventfd_read(void)
356 {
357 	struct io_uring ring;
358 	int fd, ret;
359 	eventfd_t event;
360 	struct io_uring_sqe *sqe;
361 	struct io_uring_cqe *cqe;
362 
363 	if (no_read)
364 		return 0;
365 	ret = io_uring_queue_init(8, &ring, 0);
366 	if (ret)
367 		return ret;
368 
369 	fd = eventfd(1, 0);
370 	if (fd < 0) {
371 		perror("eventfd");
372 		return 1;
373 	}
374 	sqe = io_uring_get_sqe(&ring);
375 	io_uring_prep_read(sqe, fd, &event, sizeof(eventfd_t), 0);
376 	ret = io_uring_submit(&ring);
377 	if (ret != 1) {
378 		fprintf(stderr, "submitted %d\n", ret);
379 		return 1;
380 	}
381 	eventfd_write(fd, 1);
382 	ret = io_uring_wait_cqe(&ring, &cqe);
383 	if (ret) {
384 		fprintf(stderr, "wait_cqe=%d\n", ret);
385 		return 1;
386 	}
387 	if (cqe->res == -EINVAL) {
388 		fprintf(stdout, "eventfd IO not supported, skipping\n");
389 	} else if (cqe->res != sizeof(eventfd_t)) {
390 		fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res,
391 						(int) sizeof(eventfd_t));
392 		return 1;
393 	}
394 	io_uring_cqe_seen(&ring, cqe);
395 	return 0;
396 }
397 
test_buf_select_short(const char * filename,int nonvec)398 static int test_buf_select_short(const char *filename, int nonvec)
399 {
400 	struct io_uring_sqe *sqe;
401 	struct io_uring_cqe *cqe;
402 	struct io_uring ring;
403 	int ret, i, exp_len;
404 
405 	if (no_buf_select)
406 		return 0;
407 
408 	ret = io_uring_queue_init(64, &ring, 0);
409 	if (ret) {
410 		fprintf(stderr, "ring create failed: %d\n", ret);
411 		return 1;
412 	}
413 
414 	exp_len = 0;
415 	for (i = 0; i < BUFFERS; i++) {
416 		sqe = io_uring_get_sqe(&ring);
417 		io_uring_prep_provide_buffers(sqe, vecs[i].iov_base,
418 						vecs[i].iov_len / 2, 1, 1, i);
419 		if (!exp_len)
420 			exp_len = vecs[i].iov_len / 2;
421 	}
422 
423 	ret = io_uring_submit(&ring);
424 	if (ret != BUFFERS) {
425 		fprintf(stderr, "submit: %d\n", ret);
426 		return -1;
427 	}
428 
429 	for (i = 0; i < BUFFERS; i++) {
430 		ret = io_uring_wait_cqe(&ring, &cqe);
431 		if (cqe->res < 0) {
432 			fprintf(stderr, "cqe->res=%d\n", cqe->res);
433 			return 1;
434 		}
435 		io_uring_cqe_seen(&ring, cqe);
436 	}
437 
438 	ret = __test_io(filename, &ring, 0, 0, 0, 0, nonvec, 1, 1, exp_len);
439 
440 	io_uring_queue_exit(&ring);
441 	return ret;
442 }
443 
provide_buffers_iovec(struct io_uring * ring,int bgid)444 static int provide_buffers_iovec(struct io_uring *ring, int bgid)
445 {
446 	struct io_uring_sqe *sqe;
447 	struct io_uring_cqe *cqe;
448 	int i, ret;
449 
450 	for (i = 0; i < BUFFERS; i++) {
451 		sqe = io_uring_get_sqe(ring);
452 		io_uring_prep_provide_buffers(sqe, vecs[i].iov_base,
453 						vecs[i].iov_len, 1, bgid, i);
454 	}
455 
456 	ret = io_uring_submit(ring);
457 	if (ret != BUFFERS) {
458 		fprintf(stderr, "submit: %d\n", ret);
459 		return -1;
460 	}
461 
462 	for (i = 0; i < BUFFERS; i++) {
463 		ret = io_uring_wait_cqe(ring, &cqe);
464 		if (ret) {
465 			fprintf(stderr, "wait_cqe=%d\n", ret);
466 			return 1;
467 		}
468 		if (cqe->res < 0) {
469 			fprintf(stderr, "cqe->res=%d\n", cqe->res);
470 			return 1;
471 		}
472 		io_uring_cqe_seen(ring, cqe);
473 	}
474 
475 	return 0;
476 }
477 
test_buf_select(const char * filename,int nonvec)478 static int test_buf_select(const char *filename, int nonvec)
479 {
480 	struct io_uring_probe *p;
481 	struct io_uring ring;
482 	int ret, i;
483 
484 	ret = io_uring_queue_init(64, &ring, 0);
485 	if (ret) {
486 		fprintf(stderr, "ring create failed: %d\n", ret);
487 		return 1;
488 	}
489 
490 	p = io_uring_get_probe_ring(&ring);
491 	if (!p || !io_uring_opcode_supported(p, IORING_OP_PROVIDE_BUFFERS)) {
492 		no_buf_select = 1;
493 		fprintf(stdout, "Buffer select not supported, skipping\n");
494 		return 0;
495 	}
496 	free(p);
497 
498 	/*
499 	 * Write out data with known pattern
500 	 */
501 	for (i = 0; i < BUFFERS; i++)
502 		memset(vecs[i].iov_base, i, vecs[i].iov_len);
503 
504 	ret = __test_io(filename, &ring, 1, 0, 0, 0, 0, 0, 1, BS);
505 	if (ret) {
506 		fprintf(stderr, "failed writing data\n");
507 		return 1;
508 	}
509 
510 	for (i = 0; i < BUFFERS; i++)
511 		memset(vecs[i].iov_base, 0x55, vecs[i].iov_len);
512 
513 	ret = provide_buffers_iovec(&ring, 1);
514 	if (ret)
515 		return ret;
516 
517 	ret = __test_io(filename, &ring, 0, 0, 0, 0, nonvec, 1, 1, BS);
518 	io_uring_queue_exit(&ring);
519 	return ret;
520 }
521 
test_rem_buf(int batch,int sqe_flags)522 static int test_rem_buf(int batch, int sqe_flags)
523 {
524 	struct io_uring_sqe *sqe;
525 	struct io_uring_cqe *cqe;
526 	struct io_uring ring;
527 	int left, ret, nr = 0;
528 	int bgid = 1;
529 
530 	if (no_buf_select)
531 		return 0;
532 
533 	ret = io_uring_queue_init(64, &ring, 0);
534 	if (ret) {
535 		fprintf(stderr, "ring create failed: %d\n", ret);
536 		return 1;
537 	}
538 
539 	ret = provide_buffers_iovec(&ring, bgid);
540 	if (ret)
541 		return ret;
542 
543 	left = BUFFERS;
544 	while (left) {
545 		int to_rem = (left < batch) ? left : batch;
546 
547 		left -= to_rem;
548 		sqe = io_uring_get_sqe(&ring);
549 		io_uring_prep_remove_buffers(sqe, to_rem, bgid);
550 		sqe->user_data = to_rem;
551 		sqe->flags |= sqe_flags;
552 		++nr;
553 	}
554 
555 	ret = io_uring_submit(&ring);
556 	if (ret != nr) {
557 		fprintf(stderr, "submit: %d\n", ret);
558 		return -1;
559 	}
560 
561 	for (; nr > 0; nr--) {
562 		ret = io_uring_wait_cqe(&ring, &cqe);
563 		if (ret) {
564 			fprintf(stderr, "wait_cqe=%d\n", ret);
565 			return 1;
566 		}
567 		if (cqe->res != cqe->user_data) {
568 			fprintf(stderr, "cqe->res=%d\n", cqe->res);
569 			return 1;
570 		}
571 		io_uring_cqe_seen(&ring, cqe);
572 	}
573 
574 	io_uring_queue_exit(&ring);
575 	return ret;
576 }
577 
test_io_link(const char * file)578 static int test_io_link(const char *file)
579 {
580 	const int nr_links = 100;
581 	const int link_len = 100;
582 	const int nr_sqes = nr_links * link_len;
583 	struct io_uring_sqe *sqe;
584 	struct io_uring_cqe *cqe;
585 	struct io_uring ring;
586 	int i, j, fd, ret;
587 
588 	fd = open(file, O_WRONLY);
589 	if (fd < 0) {
590 		perror("file open");
591 		goto err;
592 	}
593 
594 	ret = io_uring_queue_init(nr_sqes, &ring, 0);
595 	if (ret) {
596 		fprintf(stderr, "ring create failed: %d\n", ret);
597 		goto err;
598 	}
599 
600 	for (i = 0; i < nr_links; ++i) {
601 		for (j = 0; j < link_len; ++j) {
602 			sqe = io_uring_get_sqe(&ring);
603 			if (!sqe) {
604 				fprintf(stderr, "sqe get failed\n");
605 				goto err;
606 			}
607 			io_uring_prep_writev(sqe, fd, &vecs[0], 1, 0);
608 			sqe->flags |= IOSQE_ASYNC;
609 			if (j != link_len - 1)
610 				sqe->flags |= IOSQE_IO_LINK;
611 		}
612 	}
613 
614 	ret = io_uring_submit(&ring);
615 	if (ret != nr_sqes) {
616 		ret = io_uring_peek_cqe(&ring, &cqe);
617 		if (!ret && cqe->res == -EINVAL) {
618 			fprintf(stdout, "IOSQE_ASYNC not supported, skipped\n");
619 			goto out;
620 		}
621 		fprintf(stderr, "submit got %d, wanted %d\n", ret, nr_sqes);
622 		goto err;
623 	}
624 
625 	for (i = 0; i < nr_sqes; i++) {
626 		ret = io_uring_wait_cqe(&ring, &cqe);
627 		if (ret) {
628 			fprintf(stderr, "wait_cqe=%d\n", ret);
629 			goto err;
630 		}
631 		if (cqe->res == -EINVAL) {
632 			if (!warned) {
633 				fprintf(stdout, "Non-vectored IO not "
634 					"supported, skipping\n");
635 				warned = 1;
636 				no_read = 1;
637 			}
638 		} else if (cqe->res != BS) {
639 			fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res, BS);
640 			goto err;
641 		}
642 		io_uring_cqe_seen(&ring, cqe);
643 	}
644 
645 out:
646 	io_uring_queue_exit(&ring);
647 	close(fd);
648 	return 0;
649 err:
650 	if (fd != -1)
651 		close(fd);
652 	return 1;
653 }
654 
test_write_efbig(void)655 static int test_write_efbig(void)
656 {
657 	struct io_uring_sqe *sqe;
658 	struct io_uring_cqe *cqe;
659 	struct io_uring ring;
660 	struct rlimit rlim, old_rlim;
661 	int i, fd, ret;
662 	loff_t off;
663 
664 	if (geteuid()) {
665 		fprintf(stdout, "Not root, skipping %s\n", __FUNCTION__);
666 		return 0;
667 	}
668 
669 	if (getrlimit(RLIMIT_FSIZE, &old_rlim) < 0) {
670 		perror("getrlimit");
671 		return 1;
672 	}
673 	rlim = old_rlim;
674 	rlim.rlim_cur = 64 * 1024;
675 	rlim.rlim_max = 64 * 1024;
676 	if (setrlimit(RLIMIT_FSIZE, &rlim) < 0) {
677 		perror("setrlimit");
678 		return 1;
679 	}
680 
681 	fd = open(".efbig", O_WRONLY | O_CREAT, 0644);
682 	if (fd < 0) {
683 		perror("file open");
684 		goto err;
685 	}
686 
687 	ret = io_uring_queue_init(32, &ring, 0);
688 	if (ret) {
689 		fprintf(stderr, "ring create failed: %d\n", ret);
690 		goto err;
691 	}
692 
693 	off = 0;
694 	for (i = 0; i < 32; i++) {
695 		sqe = io_uring_get_sqe(&ring);
696 		if (!sqe) {
697 			fprintf(stderr, "sqe get failed\n");
698 			goto err;
699 		}
700 		io_uring_prep_writev(sqe, fd, &vecs[i], 1, off);
701 		off += BS;
702 	}
703 
704 	ret = io_uring_submit(&ring);
705 	if (ret != 32) {
706 		fprintf(stderr, "submit got %d, wanted %d\n", ret, 32);
707 		goto err;
708 	}
709 
710 	for (i = 0; i < 32; i++) {
711 		ret = io_uring_wait_cqe(&ring, &cqe);
712 		if (ret) {
713 			fprintf(stderr, "wait_cqe=%d\n", ret);
714 			goto err;
715 		}
716 		if (i < 16) {
717 			if (cqe->res != BS) {
718 				fprintf(stderr, "bad write: %d\n", cqe->res);
719 				goto err;
720 			}
721 		} else {
722 			if (cqe->res != -EFBIG) {
723 				fprintf(stderr, "Expected -EFBIG: %d\n", cqe->res);
724 				goto err;
725 			}
726 		}
727 		io_uring_cqe_seen(&ring, cqe);
728 	}
729 
730 	io_uring_queue_exit(&ring);
731 	close(fd);
732 	unlink(".efbig");
733 
734 	if (setrlimit(RLIMIT_FSIZE, &old_rlim) < 0) {
735 		perror("setrlimit");
736 		return 1;
737 	}
738 	return 0;
739 err:
740 	if (fd != -1)
741 		close(fd);
742 	unlink(".efbig");
743 	return 1;
744 }
745 
main(int argc,char * argv[])746 int main(int argc, char *argv[])
747 {
748 	int i, ret, nr;
749 	char *fname;
750 
751 	if (argc > 1) {
752 		fname = argv[1];
753 	} else {
754 		fname = ".basic-rw";
755 		t_create_file(fname, FILE_SIZE);
756 	}
757 
758 	vecs = t_create_buffers(BUFFERS, BS);
759 
760 	/* if we don't have nonvec read, skip testing that */
761 	nr = has_nonvec_read() ? 32 : 16;
762 
763 	for (i = 0; i < nr; i++) {
764 		int write = (i & 1) != 0;
765 		int buffered = (i & 2) != 0;
766 		int sqthread = (i & 4) != 0;
767 		int fixed = (i & 8) != 0;
768 		int nonvec = (i & 16) != 0;
769 
770 		ret = test_io(fname, write, buffered, sqthread, fixed, nonvec,
771 			      BS);
772 		if (ret) {
773 			fprintf(stderr, "test_io failed %d/%d/%d/%d/%d\n",
774 				write, buffered, sqthread, fixed, nonvec);
775 			goto err;
776 		}
777 	}
778 
779 	ret = test_buf_select(fname, 1);
780 	if (ret) {
781 		fprintf(stderr, "test_buf_select nonvec failed\n");
782 		goto err;
783 	}
784 
785 	ret = test_buf_select(fname, 0);
786 	if (ret) {
787 		fprintf(stderr, "test_buf_select vec failed\n");
788 		goto err;
789 	}
790 
791 	ret = test_buf_select_short(fname, 1);
792 	if (ret) {
793 		fprintf(stderr, "test_buf_select_short nonvec failed\n");
794 		goto err;
795 	}
796 
797 	ret = test_buf_select_short(fname, 0);
798 	if (ret) {
799 		fprintf(stderr, "test_buf_select_short vec failed\n");
800 		goto err;
801 	}
802 
803 	ret = test_eventfd_read();
804 	if (ret) {
805 		fprintf(stderr, "test_eventfd_read failed\n");
806 		goto err;
807 	}
808 
809 	ret = read_poll_link(fname);
810 	if (ret) {
811 		fprintf(stderr, "read_poll_link failed\n");
812 		goto err;
813 	}
814 
815 	ret = test_io_link(fname);
816 	if (ret) {
817 		fprintf(stderr, "test_io_link failed\n");
818 		goto err;
819 	}
820 
821 	ret = test_write_efbig();
822 	if (ret) {
823 		fprintf(stderr, "test_write_efbig failed\n");
824 		goto err;
825 	}
826 
827 	ret = test_rem_buf(1, 0);
828 	if (ret) {
829 		fprintf(stderr, "test_rem_buf by 1 failed\n");
830 		goto err;
831 	}
832 
833 	ret = test_rem_buf(10, 0);
834 	if (ret) {
835 		fprintf(stderr, "test_rem_buf by 10 failed\n");
836 		goto err;
837 	}
838 
839 	ret = test_rem_buf(2, IOSQE_IO_LINK);
840 	if (ret) {
841 		fprintf(stderr, "test_rem_buf link failed\n");
842 		goto err;
843 	}
844 
845 	ret = test_rem_buf(2, IOSQE_ASYNC);
846 	if (ret) {
847 		fprintf(stderr, "test_rem_buf async failed\n");
848 		goto err;
849 	}
850 
851 	srand((unsigned)time(NULL));
852 	if (create_nonaligned_buffers()) {
853 		fprintf(stderr, "file creation failed\n");
854 		goto err;
855 	}
856 
857 	/* test fixed bufs with non-aligned len/offset */
858 	for (i = 0; i < nr; i++) {
859 		int write = (i & 1) != 0;
860 		int buffered = (i & 2) != 0;
861 		int sqthread = (i & 4) != 0;
862 		int fixed = (i & 8) != 0;
863 		int nonvec = (i & 16) != 0;
864 
865 		/* direct IO requires alignment, skip it */
866 		if (!buffered || !fixed || nonvec)
867 			continue;
868 
869 		ret = test_io(fname, write, buffered, sqthread, fixed, nonvec,
870 			      -1);
871 		if (ret) {
872 			fprintf(stderr, "test_io failed %d/%d/%d/%d/%d\n",
873 				write, buffered, sqthread, fixed, nonvec);
874 			goto err;
875 		}
876 	}
877 
878 	if (fname != argv[1])
879 		unlink(fname);
880 	return 0;
881 err:
882 	if (fname != argv[1])
883 		unlink(fname);
884 	return 1;
885 }
886