• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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