xref: /aosp_15_r20/external/liburing/test/link_drain.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
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