xref: /aosp_15_r20/external/liburing/test/sq-poll-dup.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: test SQPOLL with IORING_SETUP_ATTACH_WQ and closing of
4  * the original ring descriptor.
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 #include <sys/types.h>
13 #include <sys/eventfd.h>
14 #include <sys/resource.h>
15 
16 #include "helpers.h"
17 #include "liburing.h"
18 
19 #define FILE_SIZE	(128 * 1024 * 1024)
20 #define BS		4096
21 #define BUFFERS		64
22 
23 #define NR_RINGS	4
24 
25 static struct iovec *vecs;
26 static struct io_uring rings[NR_RINGS];
27 
wait_io(struct io_uring * ring,int nr_ios)28 static int wait_io(struct io_uring *ring, int nr_ios)
29 {
30 	struct io_uring_cqe *cqe;
31 	int ret;
32 
33 	while (nr_ios) {
34 		ret = io_uring_wait_cqe(ring, &cqe);
35 		if (ret) {
36 			fprintf(stderr, "wait_ret=%d\n", ret);
37 			return 1;
38 		}
39 		if (cqe->res != BS) {
40 			fprintf(stderr, "Unexpected ret %d\n", cqe->res);
41 			return 1;
42 		}
43 		io_uring_cqe_seen(ring, cqe);
44 		nr_ios--;
45 	}
46 
47 	return 0;
48 }
49 
queue_io(struct io_uring * ring,int fd,int nr_ios)50 static int queue_io(struct io_uring *ring, int fd, int nr_ios)
51 {
52 	unsigned long off;
53 	int i;
54 
55 	i = 0;
56 	off = 0;
57 	while (nr_ios) {
58 		struct io_uring_sqe *sqe;
59 
60 		sqe = io_uring_get_sqe(ring);
61 		if (!sqe)
62 			break;
63 		io_uring_prep_read(sqe, fd, vecs[i].iov_base, vecs[i].iov_len, off);
64 		nr_ios--;
65 		i++;
66 		off += BS;
67 	}
68 
69 	io_uring_submit(ring);
70 	return i;
71 }
72 
do_io(int fd,int ring_start,int ring_end)73 static int do_io(int fd, int ring_start, int ring_end)
74 {
75 	int i, rets[NR_RINGS];
76 	unsigned ios = 0;
77 
78 	while (ios < 32) {
79 		for (i = ring_start; i < ring_end; i++) {
80 			int ret = queue_io(&rings[i], fd, BUFFERS);
81 			if (ret < 0)
82 				goto err;
83 			rets[i] = ret;
84 		}
85 		for (i = ring_start; i < ring_end; i++) {
86 			if (wait_io(&rings[i], rets[i]))
87 				goto err;
88 		}
89 		ios += BUFFERS;
90 	}
91 
92 	return 0;
93 err:
94 	return 1;
95 }
96 
test(int fd,int do_dup_and_close,int close_ring)97 static int test(int fd, int do_dup_and_close, int close_ring)
98 {
99 	int i, ret, ring_fd;
100 
101 	for (i = 0; i < NR_RINGS; i++) {
102 		struct io_uring_params p = { };
103 
104 		p.flags = IORING_SETUP_SQPOLL;
105 		p.sq_thread_idle = 100;
106 		if (i) {
107 			p.wq_fd = rings[0].ring_fd;
108 			p.flags |= IORING_SETUP_ATTACH_WQ;
109 		}
110 		ret = io_uring_queue_init_params(BUFFERS, &rings[i], &p);
111 		if (ret) {
112 			fprintf(stderr, "queue_init: %d/%d\n", ret, i);
113 			goto err;
114 		}
115 		/* no sharing for non-fixed either */
116 		if (!(p.features & IORING_FEAT_SQPOLL_NONFIXED)) {
117 			fprintf(stdout, "No SQPOLL sharing, skipping\n");
118 			return 0;
119 		}
120 	}
121 
122 	/* test all rings */
123 	if (do_io(fd, 0, NR_RINGS))
124 		goto err;
125 
126 	/* dup and close original ring fd */
127 	ring_fd = dup(rings[0].ring_fd);
128 	if (close_ring)
129 		close(rings[0].ring_fd);
130 	rings[0].ring_fd = rings[0].enter_ring_fd = ring_fd;
131 	if (do_dup_and_close)
132 		goto done;
133 
134 	/* test all but closed one */
135 	if (do_io(fd, 1, NR_RINGS))
136 		goto err;
137 
138 	/* test closed one */
139 	if (do_io(fd, 0, 1))
140 		goto err;
141 
142 	/* make sure thread is idle so we enter the kernel */
143 	usleep(200000);
144 
145 	/* test closed one */
146 	if (do_io(fd, 0, 1))
147 		goto err;
148 
149 
150 done:
151 	for (i = 0; i < NR_RINGS; i++)
152 		io_uring_queue_exit(&rings[i]);
153 
154 	return 0;
155 err:
156 	return 1;
157 }
158 
main(int argc,char * argv[])159 int main(int argc, char *argv[])
160 {
161 	char *fname;
162 	int ret, fd;
163 
164 	if (argc > 1) {
165 		fname = argv[1];
166 	} else {
167 		fname = ".basic-rw-poll-dup";
168 		t_create_file(fname, FILE_SIZE);
169 	}
170 
171 	vecs = t_create_buffers(BUFFERS, BS);
172 
173 	fd = open(fname, O_RDONLY | O_DIRECT);
174 	if (fname != argv[1])
175 		unlink(fname);
176 
177 	if (fd < 0) {
178 		perror("open");
179 		return -1;
180 	}
181 
182 	ret = test(fd, 0, 0);
183 	if (ret) {
184 		fprintf(stderr, "test 0 0 failed\n");
185 		goto err;
186 	}
187 
188 	ret = test(fd, 0, 1);
189 	if (ret) {
190 		fprintf(stderr, "test 0 1 failed\n");
191 		goto err;
192 	}
193 
194 
195 	ret = test(fd, 1, 0);
196 	if (ret) {
197 		fprintf(stderr, "test 1 0 failed\n");
198 		goto err;
199 	}
200 
201 	return 0;
202 err:
203 	return 1;
204 }
205