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