• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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