1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: link <open file><read from file><close file>
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 #define MAX_FILES 8
17 #define FNAME ".link.direct"
18
test(struct io_uring * ring,int skip_success,int drain,int async)19 static int test(struct io_uring *ring, int skip_success, int drain, int async)
20 {
21 struct io_uring_cqe *cqe;
22 struct io_uring_sqe *sqe;
23 char buf[4096];
24 int ret, i;
25
26 /* drain and cqe skip are mutually exclusive */
27 if (skip_success && drain)
28 return 1;
29
30 sqe = io_uring_get_sqe(ring);
31 io_uring_prep_openat_direct(sqe, AT_FDCWD, FNAME, O_RDONLY, 0, 0);
32 if (!drain)
33 sqe->flags |= IOSQE_IO_LINK;
34 if (skip_success)
35 sqe->flags |= IOSQE_CQE_SKIP_SUCCESS;
36 if (async)
37 sqe->flags |= IOSQE_ASYNC;
38 sqe->user_data = 1;
39
40 sqe = io_uring_get_sqe(ring);
41 io_uring_prep_read(sqe, 0, buf, sizeof(buf), 0);
42 sqe->flags |= IOSQE_FIXED_FILE;
43 if (drain)
44 sqe->flags |= IOSQE_IO_DRAIN;
45 else
46 sqe->flags |= IOSQE_IO_LINK;
47 if (async)
48 sqe->flags |= IOSQE_ASYNC;
49 sqe->user_data = 2;
50
51 sqe = io_uring_get_sqe(ring);
52 io_uring_prep_close_direct(sqe, 0);
53 sqe->user_data = 3;
54 if (skip_success)
55 sqe->flags |= IOSQE_CQE_SKIP_SUCCESS;
56 if (drain)
57 sqe->flags |= IOSQE_IO_DRAIN;
58 if (async)
59 sqe->flags |= IOSQE_ASYNC;
60
61 ret = io_uring_submit(ring);
62 if (ret != 3) {
63 fprintf(stderr, "sqe submit failed: %d\n", ret);
64 goto err;
65 }
66
67 if (skip_success) {
68 ret = io_uring_wait_cqe(ring, &cqe);
69 if (ret < 0) {
70 fprintf(stderr, "wait completion %d\n", ret);
71 goto err;
72 }
73 if (cqe->user_data != 2) {
74 fprintf(stderr, "Unexpected cqe %lu/%d\n",
75 (unsigned long) cqe->user_data,
76 cqe->res);
77 goto err;
78 }
79 if (cqe->res != sizeof(buf)) {
80 fprintf(stderr, "bad read %d\n", cqe->res);
81 goto err;
82 }
83 io_uring_cqe_seen(ring, cqe);
84 return 0;
85 }
86
87 for (i = 0; i < 3; i++) {
88 ret = io_uring_wait_cqe(ring, &cqe);
89 if (ret < 0) {
90 fprintf(stderr, "wait completion %d\n", ret);
91 goto err;
92 }
93 switch (cqe->user_data) {
94 case 1:
95 if (cqe->res) {
96 fprintf(stderr, "bad open %d\n", cqe->res);
97 goto err;
98 }
99 break;
100 case 2:
101 if (cqe->res != sizeof(buf)) {
102 fprintf(stderr, "bad read %d\n", cqe->res);
103 goto err;
104 }
105 break;
106 case 3:
107 if (cqe->res) {
108 fprintf(stderr, "bad close %d\n", cqe->res);
109 goto err;
110 }
111 break;
112 }
113 io_uring_cqe_seen(ring, cqe);
114 }
115
116 return 0;
117 err:
118 return 1;
119 }
120
main(int argc,char * argv[])121 int main(int argc, char *argv[])
122 {
123 struct io_uring ring;
124 struct io_uring_params p = { };
125 int ret, files[MAX_FILES];
126
127 if (argc > 1)
128 return 0;
129
130 ret = io_uring_queue_init_params(8, &ring, &p);
131 if (ret) {
132 fprintf(stderr, "ring setup failed: %d\n", ret);
133 return 1;
134 }
135 if (!(p.features & IORING_FEAT_CQE_SKIP))
136 return 0;
137
138 memset(files, -1, sizeof(files));
139 ret = io_uring_register_files(&ring, files, ARRAY_SIZE(files));
140 if (ret) {
141 fprintf(stderr, "Failed registering files\n");
142 return 1;
143 }
144
145 t_create_file(FNAME, 4096);
146
147 ret = test(&ring, 0, 0, 0);
148 if (ret) {
149 fprintf(stderr, "test 0 0 0 failed\n");
150 goto err;
151 }
152
153 ret = test(&ring, 0, 1, 0);
154 if (ret) {
155 fprintf(stderr, "test 0 1 0 failed\n");
156 goto err;
157 }
158
159 ret = test(&ring, 0, 0, 1);
160 if (ret) {
161 fprintf(stderr, "test 0 0 1 failed\n");
162 goto err;
163 }
164
165 ret = test(&ring, 0, 1, 1);
166 if (ret) {
167 fprintf(stderr, "test 0 1 1 failed\n");
168 goto err;
169 }
170
171 ret = test(&ring, 1, 0, 0);
172 if (ret) {
173 fprintf(stderr, "test 1 0 0 failed\n");
174 goto err;
175 }
176
177 ret = test(&ring, 1, 0, 1);
178 if (ret) {
179 fprintf(stderr, "test 1 0 1 failed\n");
180 goto err;
181 }
182
183 unlink(FNAME);
184 return 0;
185 err:
186 unlink(FNAME);
187 return 1;
188 }
189