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