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