blob: 05833d47de7b787df08121d56ef056d5964598eb [file] [log] [blame]
Jens Axboee5024352020-02-11 20:34:12 -07001/* SPDX-License-Identifier: MIT */
Pavel Begunkov6f6de472019-10-25 12:48:30 +03002#include <errno.h>
3#include <stdio.h>
4#include <unistd.h>
5#include <stdlib.h>
6#include <string.h>
7#include <fcntl.h>
8#include <sys/uio.h>
9#include <stdbool.h>
10
11#include "liburing.h"
12
13struct test_context {
14 struct io_uring *ring;
15 struct io_uring_sqe **sqes;
16 struct io_uring_cqe *cqes;
17 int nr;
18};
19
20static void free_context(struct test_context *ctx)
21{
22 free(ctx->sqes);
23 free(ctx->cqes);
24 memset(ctx, 0, sizeof(*ctx));
25}
26
27static int init_context(struct test_context *ctx, struct io_uring *ring, int nr)
28{
29 struct io_uring_sqe *sqe;
30 int i;
31
32 memset(ctx, 0, sizeof(*ctx));
33 ctx->nr = nr;
34 ctx->ring = ring;
35 ctx->sqes = malloc(nr * sizeof(*ctx->sqes));
36 ctx->cqes = malloc(nr * sizeof(*ctx->cqes));
37
38 if (!ctx->sqes || !ctx->cqes)
39 goto err;
40
41 for (i = 0; i < nr; i++) {
42 sqe = io_uring_get_sqe(ring);
43 if (!sqe)
44 goto err;
45 io_uring_prep_nop(sqe);
46 sqe->user_data = i;
47 ctx->sqes[i] = sqe;
48 }
49
50 return 0;
51err:
52 free_context(ctx);
53 printf("init context failed\n");
54 return 1;
55}
56
57static int wait_cqes(struct test_context *ctx)
58{
59 int ret, i;
60 struct io_uring_cqe *cqe;
61
62 for (i = 0; i < ctx->nr; i++) {
63 ret = io_uring_wait_cqe(ctx->ring, &cqe);
64
65 if (ret < 0) {
66 printf("wait_cqes: wait completion %d\n", ret);
67 return 1;
68 }
69 memcpy(&ctx->cqes[i], cqe, sizeof(*cqe));
70 io_uring_cqe_seen(ctx->ring, cqe);
71 }
72
73 return 0;
74}
75
76static int test_cancelled_userdata(struct io_uring *ring)
77{
78 struct test_context ctx;
79 int ret, i, nr = 100;
80
81 if (init_context(&ctx, ring, nr))
82 return 1;
83
84 for (i = 0; i < nr; i++)
85 ctx.sqes[i]->flags |= IOSQE_IO_LINK;
86
87 ret = io_uring_submit(ring);
88 if (ret <= 0) {
89 printf("sqe submit failed: %d\n", ret);
90 goto err;
91 }
92
93 if (wait_cqes(&ctx))
94 goto err;
95
Joseph Qia8b3b782019-10-30 15:16:30 +080096 for (i = 0; i < nr; i++) {
Pavel Begunkov6f6de472019-10-25 12:48:30 +030097 if (i != ctx.cqes[i].user_data) {
98 printf("invalid user data\n");
99 goto err;
100 }
101 }
102
103 free_context(&ctx);
104 return 0;
105err:
106 free_context(&ctx);
107 return 1;
108}
109
110static int test_thread_link_cancel(struct io_uring *ring)
111{
112 struct test_context ctx;
113 int ret, i, nr = 100;
114
115 if (init_context(&ctx, ring, nr))
116 return 1;
117
118 for (i = 0; i < nr; i++)
119 ctx.sqes[i]->flags |= IOSQE_IO_LINK;
120
121 ret = io_uring_submit(ring);
122 if (ret <= 0) {
123 printf("sqe submit failed: %d\n", ret);
124 goto err;
125 }
126
127 if (wait_cqes(&ctx))
128 goto err;
129
Joseph Qia8b3b782019-10-30 15:16:30 +0800130 for (i = 0; i < nr; i++) {
Pavel Begunkov6f6de472019-10-25 12:48:30 +0300131 bool fail = false;
132
133 if (i == 0)
134 fail = (ctx.cqes[i].res != -EINVAL);
135 else
136 fail = (ctx.cqes[i].res != -ECANCELED);
137
138 if (fail) {
139 printf("invalid status\n");
140 goto err;
141 }
142 }
143
144 free_context(&ctx);
145 return 0;
146err:
147 free_context(&ctx);
148 return 1;
149}
150
151static int run_drained(struct io_uring *ring, int nr)
152{
153 struct test_context ctx;
154 int ret, i;
155
156 if (init_context(&ctx, ring, nr))
157 return 1;
158
159 for (i = 0; i < nr; i++)
160 ctx.sqes[i]->flags |= IOSQE_IO_DRAIN;
161
162 ret = io_uring_submit(ring);
163 if (ret <= 0) {
164 printf("sqe submit failed: %d\n", ret);
165 goto err;
166 }
167
168 if (wait_cqes(&ctx))
169 goto err;
170
171 free_context(&ctx);
172 return 0;
173err:
174 free_context(&ctx);
175 return 1;
176}
177
178static int test_overflow_hung(struct io_uring *ring)
179{
180 struct io_uring_sqe *sqe;
181 int ret, nr = 10;
182
Jens Axboef9363392019-11-09 18:38:14 -0700183 while (*ring->cq.koverflow != 1000) {
Pavel Begunkov6f6de472019-10-25 12:48:30 +0300184 sqe = io_uring_get_sqe(ring);
185 if (!sqe) {
186 printf("get sqe failed\n");
187 return 1;
188 }
189
190 io_uring_prep_nop(sqe);
191 ret = io_uring_submit(ring);
192 if (ret <= 0) {
193 printf("sqe submit failed: %d\n", ret);
194 return 1;
195 }
196 }
197
198 return run_drained(ring, nr);
199}
200
201static int test_dropped_hung(struct io_uring *ring)
202{
203 int nr = 10;
204
205 *ring->sq.kdropped = 1000;
206 return run_drained(ring, nr);
207}
208
209int main(int argc, char *argv[])
210{
211 struct io_uring ring, poll_ring, sqthread_ring;
Jens Axboef9363392019-11-09 18:38:14 -0700212 struct io_uring_params p;
Jens Axboe9fca8692019-11-10 09:48:47 -0700213 int ret, no_sqthread = 0;
Pavel Begunkov6f6de472019-10-25 12:48:30 +0300214
Jens Axboea2141fc2020-05-19 17:36:19 -0600215 if (argc > 1)
216 return 0;
217
Jens Axboef9363392019-11-09 18:38:14 -0700218 memset(&p, 0, sizeof(p));
219 ret = io_uring_queue_init_params(1000, &ring, &p);
Pavel Begunkov6f6de472019-10-25 12:48:30 +0300220 if (ret) {
221 printf("ring setup failed\n");
222 return 1;
223 }
224
225 ret = io_uring_queue_init(1000, &poll_ring, IORING_SETUP_IOPOLL);
226 if (ret) {
227 printf("poll_ring setup failed\n");
228 return 1;
229 }
230
231 ret = io_uring_queue_init(1000, &sqthread_ring,
232 IORING_SETUP_SQPOLL | IORING_SETUP_IOPOLL);
233 if (ret) {
Jens Axboe9fca8692019-11-10 09:48:47 -0700234 if (geteuid()) {
235 no_sqthread = 1;
236 } else {
237 printf("poll_ring setup failed\n");
238 return 1;
239 }
Pavel Begunkov6f6de472019-10-25 12:48:30 +0300240 }
241
242 ret = test_cancelled_userdata(&poll_ring);
243 if (ret) {
244 printf("test_cancelled_userdata failed\n");
245 return ret;
246 }
247
Jens Axboe9fca8692019-11-10 09:48:47 -0700248 if (no_sqthread) {
249 printf("test_thread_link_cancel: skipped, not root\n");
250 } else {
251 ret = test_thread_link_cancel(&sqthread_ring);
252 if (ret) {
253 printf("test_thread_link_cancel failed\n");
254 return ret;
255 }
Pavel Begunkov6f6de472019-10-25 12:48:30 +0300256 }
257
Jens Axboef9363392019-11-09 18:38:14 -0700258 if (!(p.features & IORING_FEAT_NODROP)) {
259 ret = test_overflow_hung(&ring);
260 if (ret) {
261 printf("test_overflow_hung failed\n");
262 return ret;
263 }
Pavel Begunkov6f6de472019-10-25 12:48:30 +0300264 }
265
266 ret = test_dropped_hung(&ring);
267 if (ret) {
268 printf("test_dropped_hung failed\n");
269 return ret;
270 }
271
272 return 0;
273}