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 unlink("testfile");
115
116 iovecs.iov_base = t_malloc(4096);
117 iovecs.iov_len = 4096;
118
119 for (i = 0; i < 9; i++) {
120 sqe[i] = io_uring_get_sqe(ring);
121 if (!sqe[i]) {
122 printf("get sqe failed\n");
123 goto err;
124 }
125 }
126
127 /* normal heavy io */
128 io_uring_prep_writev(sqe[0], fd, &iovecs, 1, off);
129 sqe[0]->user_data = 0;
130
131 /* link1 io head */
132 io_uring_prep_nop(sqe[1]);
133 sqe[1]->flags |= IOSQE_IO_LINK;
134 sqe[1]->user_data = 1;
135
136 /* link1 drain io */
137 io_uring_prep_nop(sqe[2]);
138 sqe[2]->flags |= (IOSQE_IO_LINK | IOSQE_IO_DRAIN);
139 sqe[2]->user_data = 2;
140
141 /* link1 io end*/
142 io_uring_prep_nop(sqe[3]);
143 sqe[3]->user_data = 3;
144
145 /* link2 io head */
146 io_uring_prep_nop(sqe[4]);
147 sqe[4]->flags |= IOSQE_IO_LINK;
148 sqe[4]->user_data = 4;
149
150 /* link2 io */
151 io_uring_prep_nop(sqe[5]);
152 sqe[5]->flags |= IOSQE_IO_LINK;
153 sqe[5]->user_data = 5;
154
155 /* link2 drain io */
156 io_uring_prep_writev(sqe[6], fd, &iovecs, 1, off);
157 sqe[6]->flags |= (IOSQE_IO_LINK | IOSQE_IO_DRAIN);
158 sqe[6]->user_data = 6;
159
160 /* link2 io end */
161 io_uring_prep_nop(sqe[7]);
162 sqe[7]->user_data = 7;
163
164 /* normal io */
165 io_uring_prep_nop(sqe[8]);
166 sqe[8]->user_data = 8;
167
168 ret = io_uring_submit(ring);
169 if (ret < 0) {
170 printf("sqe submit failed\n");
171 goto err;
172 } else if (ret < 9) {
173 printf("Submitted only %d\n", ret);
174 goto err;
175 }
176
177 for (i = 0; i < 9; i++) {
178 ret = io_uring_wait_cqe(ring, &cqe);
179 if (ret < 0) {
180 printf("child: wait completion %d\n", ret);
181 goto err;
182 }
183
184 data[i] = cqe->user_data;
185 io_uring_cqe_seen(ring, cqe);
186 }
187
188 if (memcmp(data, expect, 9) != 0)
189 goto err;
190
191 free(iovecs.iov_base);
192 close(fd);
193 return 0;
194 err:
195 free(iovecs.iov_base);
196 close(fd);
197 return 1;
198
199 }
200
main(int argc,char * argv[])201 int main(int argc, char *argv[])
202 {
203 struct io_uring ring;
204 int i, ret;
205
206 if (argc > 1)
207 return 0;
208
209 ret = io_uring_queue_init(100, &ring, 0);
210 if (ret) {
211 printf("ring setup failed\n");
212 return 1;
213 }
214
215 for (i = 0; i < 1000; i++) {
216 ret = test_link_drain_one(&ring);
217 if (ret) {
218 fprintf(stderr, "test_link_drain_one failed\n");
219 break;
220 }
221 ret = test_link_drain_multi(&ring);
222 if (ret) {
223 fprintf(stderr, "test_link_drain_multi failed\n");
224 break;
225 }
226 }
227
228 return ret;
229 }
230