1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: test io_uring_register_sync_cancel()
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_sync_cancel;
17
test_sync_cancel_timeout(struct io_uring * ring,int async)18 static int test_sync_cancel_timeout(struct io_uring *ring, int async)
19 {
20 struct io_uring_sync_cancel_reg reg = { };
21 struct io_uring_sqe *sqe;
22 struct io_uring_cqe *cqe;
23 int ret, fds[2], to_prep;
24 char buf[32];
25
26 if (pipe(fds) < 0) {
27 perror("pipe");
28 return 1;
29 }
30
31 to_prep = 1;
32 sqe = io_uring_get_sqe(ring);
33 io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
34 sqe->user_data = 0x89;
35 if (async)
36 sqe->flags |= IOSQE_ASYNC;
37
38 ret = io_uring_submit(ring);
39 if (ret != to_prep) {
40 fprintf(stderr, "submit=%d\n", ret);
41 return 1;
42 }
43
44 usleep(10000);
45
46 reg.addr = 0x89;
47 reg.timeout.tv_nsec = 1;
48 ret = io_uring_register_sync_cancel(ring, ®);
49 if (async) {
50 /* we expect -ETIME here, but can race and get 0 */
51 if (ret != -ETIME && ret != 0) {
52 fprintf(stderr, "sync_cancel=%d\n", ret);
53 return 1;
54 }
55 } else {
56 if (ret < 0) {
57 fprintf(stderr, "sync_cancel=%d\n", ret);
58 return 1;
59 }
60 }
61
62 /*
63 * we could _almost_ use peek_cqe() here, but there is still
64 * a small gap where io-wq is done with the request and on
65 * its way to posting a completion, but hasn't done it just
66 * yet. the request is canceled and won't be doing any IO
67 * to buffers etc, but the cqe may not have quite arrived yet.
68 */
69 ret = io_uring_wait_cqe(ring, &cqe);
70 if (ret) {
71 fprintf(stderr, "peek=%d\n", ret);
72 return 1;
73 }
74 if (cqe->res >= 0) {
75 fprintf(stderr, "cqe->res=%d\n", cqe->res);
76 return 1;
77 }
78 io_uring_cqe_seen(ring, cqe);
79 return 0;
80 }
81
test_sync_cancel(struct io_uring * ring,int async,int nr_all,int use_fd)82 static int test_sync_cancel(struct io_uring *ring, int async, int nr_all,
83 int use_fd)
84 {
85 struct io_uring_sync_cancel_reg reg = { };
86 struct io_uring_sqe *sqe;
87 struct io_uring_cqe *cqe;
88 int ret, fds[2], to_prep, i;
89 char buf[32];
90
91 if (pipe(fds) < 0) {
92 perror("pipe");
93 return 1;
94 }
95
96 to_prep = 1;
97 if (nr_all)
98 to_prep = 4;
99 for (i = 0; i < to_prep; i++) {
100 sqe = io_uring_get_sqe(ring);
101 io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
102 sqe->user_data = 0x89;
103 if (async)
104 sqe->flags |= IOSQE_ASYNC;
105 }
106
107 ret = io_uring_submit(ring);
108 if (ret != to_prep) {
109 fprintf(stderr, "submit=%d\n", ret);
110 return 1;
111 }
112
113 usleep(10000);
114
115 if (!use_fd)
116 reg.addr = 0x89;
117 else
118 reg.fd = fds[0];
119 reg.timeout.tv_sec = 200;
120 if (nr_all)
121 reg.flags |= IORING_ASYNC_CANCEL_ALL;
122 if (use_fd)
123 reg.flags |= IORING_ASYNC_CANCEL_FD;
124 ret = io_uring_register_sync_cancel(ring, ®);
125 if (ret < 0) {
126 if (ret == -EINVAL && !no_sync_cancel) {
127 no_sync_cancel = 1;
128 return 0;
129 }
130 fprintf(stderr, "sync_cancel=%d\n", ret);
131 return 1;
132 }
133
134 for (i = 0; i < to_prep; i++) {
135 /*
136 * we could _almost_ use peek_cqe() here, but there is still
137 * a small gap where io-wq is done with the request and on
138 * its way to posting a completion, but hasn't done it just
139 * yet. the request is canceled and won't be doing any IO
140 * to buffers etc, but the cqe may not have quite arrived yet.
141 */
142 ret = io_uring_wait_cqe(ring, &cqe);
143 if (ret) {
144 fprintf(stderr, "peek=%d\n", ret);
145 return 1;
146 }
147 if (cqe->res >= 0) {
148 fprintf(stderr, "cqe->res=%d\n", cqe->res);
149 return 1;
150 }
151 io_uring_cqe_seen(ring, cqe);
152 }
153
154 return 0;
155 }
156
main(int argc,char * argv[])157 int main(int argc, char *argv[])
158 {
159 struct io_uring ring;
160 int ret;
161
162 if (argc > 1)
163 return T_EXIT_SKIP;
164
165 ret = t_create_ring(7, &ring, 0);
166 if (ret == T_SETUP_SKIP)
167 return T_EXIT_SKIP;
168 else if (ret != T_SETUP_OK)
169 return ret;
170
171 ret = test_sync_cancel(&ring, 0, 0, 0);
172 if (ret) {
173 fprintf(stderr, "test_sync_cancel 0 0 0 failed\n");
174 return T_EXIT_FAIL;
175 }
176 if (no_sync_cancel)
177 return T_EXIT_SKIP;
178
179 ret = test_sync_cancel(&ring, 1, 0, 0);
180 if (ret) {
181 fprintf(stderr, "test_sync_cancel 1 0 0 failed\n");
182 return T_EXIT_FAIL;
183 }
184
185 ret = test_sync_cancel(&ring, 0, 1, 0);
186 if (ret) {
187 fprintf(stderr, "test_sync_cancel 0 1 0 failed\n");
188 return T_EXIT_FAIL;
189 }
190
191 ret = test_sync_cancel(&ring, 1, 1, 0);
192 if (ret) {
193 fprintf(stderr, "test_sync_cancel 1 1 0 failed\n");
194 return T_EXIT_FAIL;
195 }
196
197 ret = test_sync_cancel(&ring, 0, 0, 1);
198 if (ret) {
199 fprintf(stderr, "test_sync_cancel 0 0 1 failed\n");
200 return T_EXIT_FAIL;
201 }
202
203 ret = test_sync_cancel(&ring, 1, 0, 1);
204 if (ret) {
205 fprintf(stderr, "test_sync_cancel 1 0 1 failed\n");
206 return T_EXIT_FAIL;
207 }
208
209 ret = test_sync_cancel(&ring, 0, 1, 1);
210 if (ret) {
211 fprintf(stderr, "test_sync_cancel 0 1 1 failed\n");
212 return T_EXIT_FAIL;
213 }
214
215 ret = test_sync_cancel(&ring, 1, 1, 1);
216 if (ret) {
217 fprintf(stderr, "test_sync_cancel 1 1 1 failed\n");
218 return T_EXIT_FAIL;
219 }
220
221 ret = test_sync_cancel_timeout(&ring, 0);
222 if (ret) {
223 fprintf(stderr, "test_sync_cancel_timeout 0\n");
224 return T_EXIT_FAIL;
225 }
226
227 /* must be last, leaves request */
228 ret = test_sync_cancel_timeout(&ring, 1);
229 if (ret) {
230 fprintf(stderr, "test_sync_cancel_timeout 1\n");
231 return T_EXIT_FAIL;
232 }
233
234 return T_EXIT_PASS;
235 }
236