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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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