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
13 #include "liburing.h"
14 #include "helpers.h"
15
16 static int no_msg;
17
test(struct io_uring * ring,unsigned dst_flags)18 static int test(struct io_uring *ring, unsigned dst_flags)
19 {
20 struct io_uring_params p = { };
21 struct io_uring_cqe *cqe;
22 struct io_uring_sqe *sqe;
23 struct io_uring dst;
24 int ret, i, err_ret = T_EXIT_FAIL;
25
26 p.flags = dst_flags | IORING_SETUP_CQSIZE;
27 p.cq_entries = 4;
28 ret = io_uring_queue_init_params(4, &dst, &p);
29 if (ret) {
30 fprintf(stderr, "Destination ring create failed %d\n", ret);
31 return T_EXIT_FAIL;
32 }
33
34 for (i = 0; i < 8; i++) {
35 sqe = io_uring_get_sqe(ring);
36 if (!sqe) {
37 fprintf(stderr, "get sqe failed\n");
38 goto err;
39 }
40
41 io_uring_prep_msg_ring(sqe, dst.ring_fd, 0x10, 0x1234, 0);
42 sqe->user_data = i + 1;
43 }
44
45 ret = io_uring_submit(ring);
46 if (ret != 8) {
47 /*
48 * Likely an old kernel that doesn't support the opcode,
49 * just skip the test.
50 */
51 if (ret == 1) {
52 err_ret = T_EXIT_SKIP;
53 no_msg = 1;
54 goto err;
55 }
56 fprintf(stderr, "sqe submit failed: %d\n", ret);
57 goto err;
58 }
59
60 for (i = 0; i < 8; i++) {
61 ret = io_uring_wait_cqe(ring, &cqe);
62 if (ret < 0) {
63 fprintf(stderr, "wait completion %d\n", ret);
64 goto err;
65 }
66 switch (cqe->user_data) {
67 case 1 ... 8:
68 if (cqe->res == -EINVAL || cqe->res == -EOPNOTSUPP) {
69 no_msg = 1;
70 goto out;
71 }
72 if (cqe->res != 0) {
73 fprintf(stderr, "cqe res %d\n", cqe->res);
74 goto err;
75 }
76 break;
77 case 0x1234:
78 if (cqe->res != 0x10) {
79 fprintf(stderr, "invalid len %x\n", cqe->res);
80 goto err;
81 }
82 break;
83 default:
84 fprintf(stderr, "Invalid user_data\n");
85 goto err;
86 }
87 io_uring_cqe_seen(ring, cqe);
88 }
89
90 for (i = 0; i < 8; i++) {
91 ret = io_uring_wait_cqe(&dst, &cqe);
92 if (ret < 0) {
93 fprintf(stderr, "wait completion %d\n", ret);
94 goto err;
95 }
96 switch (cqe->user_data) {
97 case 0x1234:
98 if (cqe->res != 0x10) {
99 fprintf(stderr, "invalid len %x\n", cqe->res);
100 goto err;
101 }
102 break;
103 default:
104 fprintf(stderr, "Invalid user_data\n");
105 goto err;
106 }
107 io_uring_cqe_seen(&dst, cqe);
108 }
109
110 out:
111 io_uring_queue_exit(&dst);
112 return no_msg ? T_EXIT_SKIP : T_EXIT_PASS;
113 err:
114 io_uring_queue_exit(&dst);
115 return err_ret;
116 }
117
main(int argc,char * argv[])118 int main(int argc, char *argv[])
119 {
120 struct io_uring src;
121 int ret;
122
123 if (argc > 1)
124 return T_EXIT_SKIP;
125
126 ret = io_uring_queue_init(8, &src, 0);
127 if (ret) {
128 fprintf(stderr, "ring setup failed: %d\n", ret);
129 return T_EXIT_FAIL;
130 }
131
132 ret = test(&src, 0);
133 if (ret && !no_msg) {
134 fprintf(stderr, "test failed\n");
135 return ret;
136 }
137 if (no_msg)
138 return T_EXIT_SKIP;
139
140 ret = test(&src, IORING_SETUP_IOPOLL);
141 if (ret) {
142 fprintf(stderr, "test IOPOLL failed\n");
143 return ret;
144 }
145
146 ret = test(&src, IORING_SETUP_DEFER_TASKRUN | IORING_SETUP_SINGLE_ISSUER);
147 if (ret) {
148 fprintf(stderr, "test defer failed\n");
149 return ret;
150 }
151
152 ret = test(&src, IORING_SETUP_DEFER_TASKRUN | IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_IOPOLL);
153 if (ret) {
154 fprintf(stderr, "test defer IOPOLL failed\n");
155 return ret;
156 }
157
158 return T_EXIT_PASS;
159 }
160