1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: test io_uring link io with drain io
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 "helpers.h"
14 #include "liburing.h"
15
test_link_drain_one(struct io_uring * ring)16 static int test_link_drain_one(struct io_uring *ring)
17 {
18 struct io_uring_cqe *cqe;
19 struct io_uring_sqe *sqe[5];
20 struct iovec iovecs;
21 int i, fd, ret;
22 off_t off = 0;
23 char data[5] = {0};
24 char expect[5] = {0, 1, 2, 3, 4};
25
26 fd = open("testfile", O_WRONLY | O_CREAT, 0644);
27 if (fd < 0) {
28 perror("open");
29 return 1;
30 }
31
32 iovecs.iov_base = t_malloc(4096);
33 iovecs.iov_len = 4096;
34
35 for (i = 0; i < 5; i++) {
36 sqe[i] = io_uring_get_sqe(ring);
37 if (!sqe[i]) {
38 printf("get sqe failed\n");
39 goto err;
40 }
41 }
42
43 /* normal heavy io */
44 io_uring_prep_writev(sqe[0], fd, &iovecs, 1, off);
45 sqe[0]->user_data = 0;
46
47 /* link io */
48 io_uring_prep_nop(sqe[1]);
49 sqe[1]->flags |= IOSQE_IO_LINK;
50 sqe[1]->user_data = 1;
51
52 /* link drain io */
53 io_uring_prep_nop(sqe[2]);
54 sqe[2]->flags |= (IOSQE_IO_LINK | IOSQE_IO_DRAIN);
55 sqe[2]->user_data = 2;
56
57 /* link io */
58 io_uring_prep_nop(sqe[3]);
59 sqe[3]->user_data = 3;
60
61 /* normal nop io */
62 io_uring_prep_nop(sqe[4]);
63 sqe[4]->user_data = 4;
64
65 ret = io_uring_submit(ring);
66 if (ret < 0) {
67 printf("sqe submit failed\n");
68 goto err;
69 } else if (ret < 5) {
70 printf("Submitted only %d\n", ret);
71 goto err;
72 }
73
74 for (i = 0; i < 5; i++) {
75 ret = io_uring_wait_cqe(ring, &cqe);
76 if (ret < 0) {
77 printf("child: wait completion %d\n", ret);
78 goto err;
79 }
80
81 data[i] = cqe->user_data;
82 io_uring_cqe_seen(ring, cqe);
83 }
84
85 if (memcmp(data, expect, 5) != 0)
86 goto err;
87
88 free(iovecs.iov_base);
89 close(fd);
90 unlink("testfile");
91 return 0;
92 err:
93 free(iovecs.iov_base);
94 close(fd);
95 unlink("testfile");
96 return 1;
97 }
98
test_link_drain_multi(struct io_uring * ring)99 int test_link_drain_multi(struct io_uring *ring)
100 {
101 struct io_uring_cqe *cqe;
102 struct io_uring_sqe *sqe[9];
103 struct iovec iovecs;
104 int i, fd, ret;
105 off_t off = 0;
106 char data[9] = {0};
107 char expect[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
108
109 fd = open("testfile", O_WRONLY | O_CREAT, 0644);
110 if (fd < 0) {
111 perror("open");
112 return 1;
113 }
114
115 iovecs.iov_base = t_malloc(4096);
116 iovecs.iov_len = 4096;
117
118 for (i = 0; i < 9; i++) {
119 sqe[i] = io_uring_get_sqe(ring);
120 if (!sqe[i]) {
121 printf("get sqe failed\n");
122 goto err;
123 }
124 }
125
126 /* normal heavy io */
127 io_uring_prep_writev(sqe[0], fd, &iovecs, 1, off);
128 sqe[0]->user_data = 0;
129
130 /* link1 io head */
131 io_uring_prep_nop(sqe[1]);
132 sqe[1]->flags |= IOSQE_IO_LINK;
133 sqe[1]->user_data = 1;
134
135 /* link1 drain io */
136 io_uring_prep_nop(sqe[2]);
137 sqe[2]->flags |= (IOSQE_IO_LINK | IOSQE_IO_DRAIN);
138 sqe[2]->user_data = 2;
139
140 /* link1 io end*/
141 io_uring_prep_nop(sqe[3]);
142 sqe[3]->user_data = 3;
143
144 /* link2 io head */
145 io_uring_prep_nop(sqe[4]);
146 sqe[4]->flags |= IOSQE_IO_LINK;
147 sqe[4]->user_data = 4;
148
149 /* link2 io */
150 io_uring_prep_nop(sqe[5]);
151 sqe[5]->flags |= IOSQE_IO_LINK;
152 sqe[5]->user_data = 5;
153
154 /* link2 drain io */
155 io_uring_prep_writev(sqe[6], fd, &iovecs, 1, off);
156 sqe[6]->flags |= (IOSQE_IO_LINK | IOSQE_IO_DRAIN);
157 sqe[6]->user_data = 6;
158
159 /* link2 io end */
160 io_uring_prep_nop(sqe[7]);
161 sqe[7]->user_data = 7;
162
163 /* normal io */
164 io_uring_prep_nop(sqe[8]);
165 sqe[8]->user_data = 8;
166
167 ret = io_uring_submit(ring);
168 if (ret < 0) {
169 printf("sqe submit failed\n");
170 goto err;
171 } else if (ret < 9) {
172 printf("Submitted only %d\n", ret);
173 goto err;
174 }
175
176 for (i = 0; i < 9; i++) {
177 ret = io_uring_wait_cqe(ring, &cqe);
178 if (ret < 0) {
179 printf("child: wait completion %d\n", ret);
180 goto err;
181 }
182
183 data[i] = cqe->user_data;
184 io_uring_cqe_seen(ring, cqe);
185 }
186
187 if (memcmp(data, expect, 9) != 0)
188 goto err;
189
190 free(iovecs.iov_base);
191 close(fd);
192 unlink("testfile");
193 return 0;
194 err:
195 free(iovecs.iov_base);
196 close(fd);
197 unlink("testfile");
198 return 1;
199
200 }
201
main(int argc,char * argv[])202 int main(int argc, char *argv[])
203 {
204 struct io_uring ring;
205 int i, ret;
206
207 if (argc > 1)
208 return 0;
209
210 ret = io_uring_queue_init(100, &ring, 0);
211 if (ret) {
212 printf("ring setup failed\n");
213 return 1;
214 }
215
216 for (i = 0; i < 1000; i++) {
217 ret = test_link_drain_one(&ring);
218 if (ret) {
219 fprintf(stderr, "test_link_drain_one failed\n");
220 break;
221 }
222 ret = test_link_drain_multi(&ring);
223 if (ret) {
224 fprintf(stderr, "test_link_drain_multi failed\n");
225 break;
226 }
227 }
228
229 return ret;
230 }
231