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