1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: test ring messaging command
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 #include <pthread.h>
13
14 #include "liburing.h"
15
16 static int no_msg;
17
test_own(struct io_uring * ring)18 static int test_own(struct io_uring *ring)
19 {
20 struct io_uring_cqe *cqe;
21 struct io_uring_sqe *sqe;
22 int ret, i;
23
24 sqe = io_uring_get_sqe(ring);
25 if (!sqe) {
26 fprintf(stderr, "get sqe failed\n");
27 goto err;
28 }
29
30 io_uring_prep_msg_ring(sqe, ring->ring_fd, 0x10, 0x1234, 0);
31 sqe->user_data = 1;
32
33 ret = io_uring_submit(ring);
34 if (ret <= 0) {
35 fprintf(stderr, "sqe submit failed: %d\n", ret);
36 goto err;
37 }
38
39 for (i = 0; i < 2; i++) {
40 ret = io_uring_wait_cqe(ring, &cqe);
41 if (ret < 0) {
42 fprintf(stderr, "wait completion %d\n", ret);
43 goto err;
44 }
45 switch (cqe->user_data) {
46 case 1:
47 if (cqe->res == -EINVAL || cqe->res == -EOPNOTSUPP) {
48 no_msg = 1;
49 return 0;
50 }
51 if (cqe->res != 0) {
52 fprintf(stderr, "cqe res %d\n", cqe->res);
53 return -1;
54 }
55 break;
56 case 0x1234:
57 if (cqe->res != 0x10) {
58 fprintf(stderr, "invalid len %x\n", cqe->res);
59 return -1;
60 }
61 break;
62 default:
63 fprintf(stderr, "Invalid user_data\n");
64 return -1;
65 }
66 io_uring_cqe_seen(ring, cqe);
67 }
68
69 return 0;
70 err:
71 return 1;
72 }
73
wait_cqe_fn(void * data)74 static void *wait_cqe_fn(void *data)
75 {
76 struct io_uring *ring = data;
77 struct io_uring_cqe *cqe;
78 int ret;
79
80 ret = io_uring_wait_cqe(ring, &cqe);
81 if (ret) {
82 fprintf(stderr, "wait cqe %d\n", ret);
83 goto err;
84 }
85
86 if (cqe->user_data != 0x5aa5) {
87 fprintf(stderr, "user_data %llx\n", (long long) cqe->user_data);
88 goto err;
89 }
90 if (cqe->res != 0x20) {
91 fprintf(stderr, "len %x\n", cqe->res);
92 goto err;
93 }
94
95 return NULL;
96 err:
97 return (void *) (unsigned long) 1;
98 }
99
test_remote(struct io_uring * ring,struct io_uring * target)100 static int test_remote(struct io_uring *ring, struct io_uring *target)
101 {
102 struct io_uring_cqe *cqe;
103 struct io_uring_sqe *sqe;
104 int ret;
105
106 sqe = io_uring_get_sqe(ring);
107 if (!sqe) {
108 fprintf(stderr, "get sqe failed\n");
109 goto err;
110 }
111
112 io_uring_prep_msg_ring(sqe, target->ring_fd, 0x20, 0x5aa5, 0);
113 sqe->user_data = 1;
114
115 ret = io_uring_submit(ring);
116 if (ret <= 0) {
117 fprintf(stderr, "sqe submit failed: %d\n", ret);
118 goto err;
119 }
120
121 ret = io_uring_wait_cqe(ring, &cqe);
122 if (ret < 0) {
123 fprintf(stderr, "wait completion %d\n", ret);
124 goto err;
125 }
126 if (cqe->res != 0) {
127 fprintf(stderr, "cqe res %d\n", cqe->res);
128 return -1;
129 }
130 if (cqe->user_data != 1) {
131 fprintf(stderr, "user_data %llx\n", (long long) cqe->user_data);
132 return -1;
133 }
134
135 io_uring_cqe_seen(ring, cqe);
136 return 0;
137 err:
138 return 1;
139 }
140
test_invalid(struct io_uring * ring)141 static int test_invalid(struct io_uring *ring)
142 {
143 struct io_uring_cqe *cqe;
144 struct io_uring_sqe *sqe;
145 int ret;
146
147 sqe = io_uring_get_sqe(ring);
148 if (!sqe) {
149 fprintf(stderr, "get sqe failed\n");
150 goto err;
151 }
152
153 io_uring_prep_msg_ring(sqe, 1, 0, 0x8989, 0);
154 sqe->user_data = 1;
155
156 ret = io_uring_submit(ring);
157 if (ret <= 0) {
158 fprintf(stderr, "sqe submit failed: %d\n", ret);
159 goto err;
160 }
161
162 ret = io_uring_wait_cqe(ring, &cqe);
163 if (ret < 0) {
164 fprintf(stderr, "wait completion %d\n", ret);
165 goto err;
166 }
167 if (cqe->res != -EBADFD) {
168 fprintf(stderr, "cqe res %d\n", cqe->res);
169 return -1;
170 }
171
172 io_uring_cqe_seen(ring, cqe);
173 return 0;
174 err:
175 return 1;
176 }
177
main(int argc,char * argv[])178 int main(int argc, char *argv[])
179 {
180 struct io_uring ring, ring2, pring;
181 pthread_t thread;
182 void *tret;
183 int ret;
184
185 if (argc > 1)
186 return 0;
187
188 ret = io_uring_queue_init(8, &ring, 0);
189 if (ret) {
190 fprintf(stderr, "ring setup failed: %d\n", ret);
191 return 1;
192 }
193 ret = io_uring_queue_init(8, &ring2, 0);
194 if (ret) {
195 fprintf(stderr, "ring setup failed: %d\n", ret);
196 return 1;
197 }
198 ret = io_uring_queue_init(8, &pring, IORING_SETUP_IOPOLL);
199 if (ret) {
200 fprintf(stderr, "ring setup failed: %d\n", ret);
201 return 1;
202 }
203
204 ret = test_own(&ring);
205 if (ret) {
206 fprintf(stderr, "test_own failed\n");
207 return ret;
208 }
209 if (no_msg) {
210 fprintf(stdout, "Skipped\n");
211 return 0;
212 }
213 ret = test_own(&pring);
214 if (ret) {
215 fprintf(stderr, "test_own iopoll failed\n");
216 return ret;
217 }
218
219 ret = test_invalid(&ring);
220 if (ret) {
221 fprintf(stderr, "test_invalid failed\n");
222 return ret;
223 }
224
225 pthread_create(&thread, NULL, wait_cqe_fn, &ring2);
226
227 ret = test_remote(&ring, &ring2);
228 if (ret) {
229 fprintf(stderr, "test_remote failed\n");
230 return ret;
231 }
232
233 pthread_join(thread, &tret);
234
235 return 0;
236 }
237