xref: /aosp_15_r20/external/liburing/test/buf-ring.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: run various shared buffer ring sanity checks
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 static int no_buf_ring;
17 
18 /* test trying to register classic group when ring group exists */
test_mixed_reg2(int bgid)19 static int test_mixed_reg2(int bgid)
20 {
21 	struct io_uring_buf_reg reg = { };
22 	struct io_uring_sqe *sqe;
23 	struct io_uring_cqe *cqe;
24 	struct io_uring ring;
25 	void *ptr, *bufs;
26 	int ret;
27 
28 	ret = t_create_ring(1, &ring, 0);
29 	if (ret == T_SETUP_SKIP)
30 		return 0;
31 	else if (ret != T_SETUP_OK)
32 		return 1;
33 
34 	if (posix_memalign(&ptr, 4096, 4096))
35 		return 1;
36 
37 	reg.ring_addr = (unsigned long) ptr;
38 	reg.ring_entries = 32;
39 	reg.bgid = bgid;
40 
41 	ret = io_uring_register_buf_ring(&ring, &reg, 0);
42 	if (ret) {
43 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
44 		return 1;
45 	}
46 
47 	/* provide classic buffers, group 1 */
48 	bufs = malloc(8 * 1024);
49 	sqe = io_uring_get_sqe(&ring);
50 	io_uring_prep_provide_buffers(sqe, bufs, 1024, 8, bgid, 0);
51 	io_uring_submit(&ring);
52 	ret = io_uring_wait_cqe(&ring, &cqe);
53 	if (ret) {
54 		fprintf(stderr, "wait_cqe %d\n", ret);
55 		return 1;
56 	}
57 	if (cqe->res != -EEXIST && cqe->res != -EINVAL) {
58 		fprintf(stderr, "cqe res %d\n", cqe->res);
59 		return 1;
60 	}
61 	io_uring_cqe_seen(&ring, cqe);
62 
63 	io_uring_queue_exit(&ring);
64 	return 0;
65 }
66 
67 /* test trying to register ring group when  classic group exists */
test_mixed_reg(int bgid)68 static int test_mixed_reg(int bgid)
69 {
70 	struct io_uring_buf_reg reg = { };
71 	struct io_uring_sqe *sqe;
72 	struct io_uring_cqe *cqe;
73 	struct io_uring ring;
74 	void *ptr, *bufs;
75 	int ret;
76 
77 	ret = t_create_ring(1, &ring, 0);
78 	if (ret == T_SETUP_SKIP)
79 		return 0;
80 	else if (ret != T_SETUP_OK)
81 		return 1;
82 
83 	/* provide classic buffers, group 1 */
84 	bufs = malloc(8 * 1024);
85 	sqe = io_uring_get_sqe(&ring);
86 	io_uring_prep_provide_buffers(sqe, bufs, 1024, 8, bgid, 0);
87 	io_uring_submit(&ring);
88 	ret = io_uring_wait_cqe(&ring, &cqe);
89 	if (ret) {
90 		fprintf(stderr, "wait_cqe %d\n", ret);
91 		return 1;
92 	}
93 	if (cqe->res) {
94 		fprintf(stderr, "cqe res %d\n", cqe->res);
95 		return 1;
96 	}
97 	io_uring_cqe_seen(&ring, cqe);
98 
99 	if (posix_memalign(&ptr, 4096, 4096))
100 		return 1;
101 
102 	reg.ring_addr = (unsigned long) ptr;
103 	reg.ring_entries = 32;
104 	reg.bgid = bgid;
105 
106 	ret = io_uring_register_buf_ring(&ring, &reg, 0);
107 	if (ret != -EEXIST) {
108 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
109 		return 1;
110 	}
111 
112 	io_uring_queue_exit(&ring);
113 	return 0;
114 }
115 
test_double_reg_unreg(int bgid)116 static int test_double_reg_unreg(int bgid)
117 {
118 	struct io_uring_buf_reg reg = { };
119 	struct io_uring ring;
120 	void *ptr;
121 	int ret;
122 
123 	ret = t_create_ring(1, &ring, 0);
124 	if (ret == T_SETUP_SKIP)
125 		return 0;
126 	else if (ret != T_SETUP_OK)
127 		return 1;
128 
129 	if (posix_memalign(&ptr, 4096, 4096))
130 		return 1;
131 
132 	reg.ring_addr = (unsigned long) ptr;
133 	reg.ring_entries = 32;
134 	reg.bgid = bgid;
135 
136 	ret = io_uring_register_buf_ring(&ring, &reg, 0);
137 	if (ret) {
138 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
139 		return 1;
140 	}
141 
142 	/* check that 2nd register with same bgid fails */
143 	reg.ring_addr = (unsigned long) ptr;
144 	reg.ring_entries = 32;
145 	reg.bgid = bgid;
146 
147 	ret = io_uring_register_buf_ring(&ring, &reg, 0);
148 	if (ret != -EEXIST) {
149 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
150 		return 1;
151 	}
152 
153 	ret = io_uring_unregister_buf_ring(&ring, bgid);
154 	if (ret) {
155 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
156 		return 1;
157 	}
158 
159 	ret = io_uring_unregister_buf_ring(&ring, bgid);
160 	if (ret != -EINVAL && ret != -ENOENT) {
161 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
162 		return 1;
163 	}
164 
165 	io_uring_queue_exit(&ring);
166 	return 0;
167 }
168 
test_reg_unreg(int bgid)169 static int test_reg_unreg(int bgid)
170 {
171 	struct io_uring_buf_reg reg = { };
172 	struct io_uring ring;
173 	void *ptr;
174 	int ret;
175 
176 	ret = t_create_ring(1, &ring, 0);
177 	if (ret == T_SETUP_SKIP)
178 		return 0;
179 	else if (ret != T_SETUP_OK)
180 		return 1;
181 
182 	if (posix_memalign(&ptr, 4096, 4096))
183 		return 1;
184 
185 	reg.ring_addr = (unsigned long) ptr;
186 	reg.ring_entries = 32;
187 	reg.bgid = bgid;
188 
189 	ret = io_uring_register_buf_ring(&ring, &reg, 0);
190 	if (ret) {
191 		if (ret == -EINVAL) {
192 			no_buf_ring = 1;
193 			return 0;
194 		}
195 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
196 		return 1;
197 	}
198 
199 	ret = io_uring_unregister_buf_ring(&ring, bgid);
200 	if (ret) {
201 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
202 		return 1;
203 	}
204 
205 	io_uring_queue_exit(&ring);
206 	return 0;
207 }
208 
test_one_read(int fd,int bgid,struct io_uring * ring)209 static int test_one_read(int fd, int bgid, struct io_uring *ring)
210 {
211 	int ret;
212 	struct io_uring_cqe *cqe;
213 	struct io_uring_sqe *sqe;
214 
215 	sqe = io_uring_get_sqe(ring);
216 	if (!sqe) {
217 		fprintf(stderr, "get sqe failed\n");
218 		return -1;
219 	}
220 
221 	io_uring_prep_read(sqe, fd, NULL, 1, 0);
222 	sqe->flags |= IOSQE_BUFFER_SELECT;
223 	sqe->buf_group = bgid;
224 	ret = io_uring_submit(ring);
225 	if (ret <= 0) {
226 		fprintf(stderr, "sqe submit failed: %d\n", ret);
227 		return -1;
228 	}
229 
230 	ret = io_uring_wait_cqe(ring, &cqe);
231 	if (ret < 0) {
232 		fprintf(stderr, "wait completion %d\n", ret);
233 		return -1;
234 	}
235 	ret = cqe->res;
236 	io_uring_cqe_seen(ring, cqe);
237 
238 	if (ret == -ENOBUFS)
239 		return ret;
240 
241 	if (ret != 1) {
242 		fprintf(stderr, "read result %d\n", ret);
243 		return -1;
244 	}
245 
246 	return cqe->flags >> 16;
247 }
248 
test_running(int bgid,int entries,int loops)249 static int test_running(int bgid, int entries, int loops)
250 {
251 	struct io_uring_buf_reg reg = { };
252 	struct io_uring ring;
253 	void *ptr;
254 	char buffer[8];
255 	int ret;
256 	int ring_size = (entries * sizeof(struct io_uring_buf) + 4095) & (~4095);
257 	int ring_mask = io_uring_buf_ring_mask(entries);
258 
259 	int loop, idx;
260 	bool *buffers;
261 	struct io_uring_buf_ring *br;
262 	int read_fd;
263 
264 	ret = t_create_ring(1, &ring, 0);
265 	if (ret == T_SETUP_SKIP)
266 		return 0;
267 	else if (ret != T_SETUP_OK)
268 		return 1;
269 
270 	if (posix_memalign(&ptr, 4096, ring_size))
271 		return 1;
272 
273 	br = (struct io_uring_buf_ring *)ptr;
274 	io_uring_buf_ring_init(br);
275 
276 	buffers = malloc(sizeof(bool) * entries);
277 	if (!buffers)
278 		return 1;
279 
280 	read_fd = open("/dev/zero", O_RDONLY);
281 	if (read_fd < 0)
282 		return 1;
283 
284 	reg.ring_addr = (unsigned long) ptr;
285 	reg.ring_entries = entries;
286 	reg.bgid = bgid;
287 
288 	ret = io_uring_register_buf_ring(&ring, &reg, 0);
289 	if (ret) {
290 		/* by now should have checked if this is supported or not */
291 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
292 		return 1;
293 	}
294 
295 	for (loop = 0; loop < loops; loop++) {
296 		memset(buffers, 0, sizeof(bool) * entries);
297 		for (idx = 0; idx < entries; idx++)
298 			io_uring_buf_ring_add(br, buffer, sizeof(buffer), idx, ring_mask, idx);
299 		io_uring_buf_ring_advance(br, entries);
300 
301 		for (idx = 0; idx < entries; idx++) {
302 			memset(buffer, 1, sizeof(buffer));
303 			ret = test_one_read(read_fd, bgid, &ring);
304 			if (ret < 0) {
305 				fprintf(stderr, "bad run %d/%d = %d\n", loop, idx, ret);
306 				return ret;
307 			}
308 			if (buffers[ret]) {
309 				fprintf(stderr, "reused buffer %d/%d = %d!\n", loop, idx, ret);
310 				return 1;
311 			}
312 			if (buffer[0] != 0) {
313 				fprintf(stderr, "unexpected read %d %d/%d = %d!\n",
314 						(int)buffer[0], loop, idx, ret);
315 				return 1;
316 			}
317 			if (buffer[1] != 1) {
318 				fprintf(stderr, "unexpected spilled read %d %d/%d = %d!\n",
319 						(int)buffer[1], loop, idx, ret);
320 				return 1;
321 			}
322 			buffers[ret] = true;
323 		}
324 		ret = test_one_read(read_fd, bgid, &ring);
325 		if (ret != -ENOBUFS) {
326 			fprintf(stderr, "expected enobufs run %d = %d\n", loop, ret);
327 			return 1;
328 		}
329 
330 	}
331 
332 	ret = io_uring_unregister_buf_ring(&ring, bgid);
333 	if (ret) {
334 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
335 		return 1;
336 	}
337 
338 	close(read_fd);
339 	io_uring_queue_exit(&ring);
340 	free(buffers);
341 	return 0;
342 }
343 
main(int argc,char * argv[])344 int main(int argc, char *argv[])
345 {
346 	int bgids[] = { 1, 127, -1 };
347 	int entries[] = {1, 32768, 4096, -1 };
348 	int ret, i;
349 
350 	if (argc > 1)
351 		return 0;
352 
353 	for (i = 0; bgids[i] != -1; i++) {
354 		ret = test_reg_unreg(bgids[i]);
355 		if (ret) {
356 			fprintf(stderr, "test_reg_unreg failed\n");
357 			return 1;
358 		}
359 		if (no_buf_ring)
360 			break;
361 
362 		ret = test_double_reg_unreg(bgids[i]);
363 		if (ret) {
364 			fprintf(stderr, "test_double_reg_unreg failed\n");
365 			return 1;
366 		}
367 
368 		ret = test_mixed_reg(bgids[i]);
369 		if (ret) {
370 			fprintf(stderr, "test_mixed_reg failed\n");
371 			return 1;
372 		}
373 
374 		ret = test_mixed_reg2(bgids[i]);
375 		if (ret) {
376 			fprintf(stderr, "test_mixed_reg2 failed\n");
377 			return 1;
378 		}
379 	}
380 
381 	for (i = 0; !no_buf_ring && entries[i] != -1; i++) {
382 		ret = test_running(2, entries[i], 3);
383 		if (ret) {
384 			fprintf(stderr, "test_running(%d) failed\n", entries[i]);
385 			return 1;
386 		}
387 	}
388 
389 	return 0;
390 }
391