blob: 79e623a310542b4d86865029a504bb888d86bdf3 [file] [log] [blame]
Jens Axboed5b94ba2020-09-09 09:31:12 -06001/* 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/poll.h>
14#include <sys/eventfd.h>
15#include <sys/resource.h>
16#include "liburing.h"
17
18#define FILE_SIZE (128 * 1024 * 1024)
19#define BS 4096
20#define BUFFERS 64
21
22#define NR_RINGS 4
23
24static struct iovec *vecs;
25static struct io_uring rings[NR_RINGS];
26
27static int create_buffers(void)
28{
29 int i;
30
31 vecs = malloc(BUFFERS * sizeof(struct iovec));
32 for (i = 0; i < BUFFERS; i++) {
33 if (posix_memalign(&vecs[i].iov_base, BS, BS))
34 return 1;
35 vecs[i].iov_len = BS;
36 }
37
38 return 0;
39}
40
41static int create_file(const char *file)
42{
43 ssize_t ret;
44 char *buf;
45 int fd;
46
47 buf = malloc(FILE_SIZE);
48 memset(buf, 0xaa, FILE_SIZE);
49
50 fd = open(file, O_WRONLY | O_CREAT, 0644);
51 if (fd < 0) {
52 perror("open file");
53 return 1;
54 }
55 ret = write(fd, buf, FILE_SIZE);
56 close(fd);
57 return ret != FILE_SIZE;
58}
59
60static int wait_io(struct io_uring *ring, int nr_ios)
61{
62 struct io_uring_cqe *cqe;
63
64 while (nr_ios) {
65 io_uring_wait_cqe(ring, &cqe);
66 if (cqe->res != BS) {
67 fprintf(stderr, "Unexpected ret %d\n", cqe->res);
68 return 1;
69 }
70 io_uring_cqe_seen(ring, cqe);
71 nr_ios--;
72 }
73
74 return 0;
75}
76
77static int queue_io(struct io_uring *ring, int fd, int nr_ios)
78{
79 unsigned long off;
Jens Axboe06486d62020-09-09 11:13:48 -060080 int i;
Jens Axboed5b94ba2020-09-09 09:31:12 -060081
82 i = 0;
83 off = 0;
84 while (nr_ios) {
85 struct io_uring_sqe *sqe;
86
87 sqe = io_uring_get_sqe(ring);
88 if (!sqe)
89 break;
90 io_uring_prep_read(sqe, fd, vecs[i].iov_base, vecs[i].iov_len, off);
91 nr_ios--;
92 i++;
93 off += BS;
94 }
95
Jens Axboed4766742020-09-09 11:11:53 -060096 io_uring_submit(ring);
97 return i;
Jens Axboed5b94ba2020-09-09 09:31:12 -060098}
99
100static int do_io(int fd, int ring_start, int ring_end)
101{
102 int i, rets[NR_RINGS];
103 unsigned ios = 0;
104
105 while (ios < 32) {
106 for (i = ring_start; i < ring_end; i++) {
107 int ret = queue_io(&rings[i], fd, BUFFERS);
108 if (ret < 0)
109 goto err;
110 rets[i] = ret;
111 }
112 for (i = ring_start; i < ring_end; i++) {
113 if (wait_io(&rings[i], rets[i]))
114 goto err;
115 }
116 ios += BUFFERS;
117 }
118
119 return 0;
120err:
121 return 1;
122}
123
Jens Axboea2cb8f92020-09-09 11:13:04 -0600124static int test(int fd, int do_dup_and_close, int close_ring)
Jens Axboed5b94ba2020-09-09 09:31:12 -0600125{
126 int i, ret, ring_fd;
127
128 for (i = 0; i < NR_RINGS; i++) {
129 struct io_uring_params p = { };
130
131 p.flags = IORING_SETUP_SQPOLL;
Jens Axboea2cb8f92020-09-09 11:13:04 -0600132 p.sq_thread_idle = 100;
Jens Axboed5b94ba2020-09-09 09:31:12 -0600133 if (i) {
134 p.wq_fd = rings[0].ring_fd;
135 p.flags |= IORING_SETUP_ATTACH_WQ;
136 }
137 ret = io_uring_queue_init_params(BUFFERS, &rings[i], &p);
138 if (ret) {
139 fprintf(stderr, "queue_init: %d/%d\n", ret, i);
140 goto err;
141 }
142 /* no sharing for non-fixed either */
143 if (!(p.features & IORING_FEAT_SQPOLL_NONFIXED)) {
144 fprintf(stdout, "No SQPOLL sharing, skipping\n");
145 return 0;
146 }
147 }
148
149 /* test all rings */
150 if (do_io(fd, 0, NR_RINGS))
151 goto err;
152
153 /* dup and close original ring fd */
154 ring_fd = dup(rings[0].ring_fd);
Jens Axboea2cb8f92020-09-09 11:13:04 -0600155 if (close_ring)
156 close(rings[0].ring_fd);
Jens Axboed5b94ba2020-09-09 09:31:12 -0600157 rings[0].ring_fd = ring_fd;
158 if (do_dup_and_close)
159 goto done;
160
161 /* test all but closed one */
162 if (do_io(fd, 1, NR_RINGS))
163 goto err;
164
165 /* test closed one */
166 if (do_io(fd, 0, 1))
167 goto err;
168
Jens Axboea2cb8f92020-09-09 11:13:04 -0600169 /* make sure thread is idle so we enter the kernel */
170 usleep(200000);
171
172 /* test closed one */
173 if (do_io(fd, 0, 1))
174 goto err;
175
176
Jens Axboed5b94ba2020-09-09 09:31:12 -0600177done:
178 for (i = 0; i < NR_RINGS; i++)
179 io_uring_queue_exit(&rings[i]);
180
181 return 0;
182err:
183 return 1;
184}
185
186int main(int argc, char *argv[])
187{
188 char *fname;
189 int ret, fd;
190
191 if (argc > 1) {
192 fname = argv[1];
193 } else {
194 fname = ".basic-rw";
195 if (create_file(fname)) {
196 fprintf(stderr, "file creation failed\n");
197 goto err;
198 }
199 }
200
201 if (create_buffers()) {
202 fprintf(stderr, "file creation failed\n");
203 goto err;
204 }
205
206 fd = open(fname, O_RDONLY | O_DIRECT);
207 if (fd < 0) {
208 perror("open");
209 return -1;
210 }
211
Jens Axboea2cb8f92020-09-09 11:13:04 -0600212 ret = test(fd, 0, 0);
Jens Axboed5b94ba2020-09-09 09:31:12 -0600213 if (ret) {
Jens Axboea2cb8f92020-09-09 11:13:04 -0600214 fprintf(stderr, "test 0 0 failed\n");
Jens Axboed5b94ba2020-09-09 09:31:12 -0600215 goto err;
216 }
217
Jens Axboea2cb8f92020-09-09 11:13:04 -0600218 ret = test(fd, 0, 1);
Jens Axboed5b94ba2020-09-09 09:31:12 -0600219 if (ret) {
Jens Axboea2cb8f92020-09-09 11:13:04 -0600220 fprintf(stderr, "test 0 1 failed\n");
221 goto err;
222 }
223
224
225 ret = test(fd, 1, 0);
226 if (ret) {
227 fprintf(stderr, "test 1 0 failed\n");
Jens Axboed5b94ba2020-09-09 09:31:12 -0600228 goto err;
229 }
230
231 if (fname != argv[1])
232 unlink(fname);
233 return 0;
234err:
235 if (fname != argv[1])
236 unlink(fname);
237 return 1;
238}