1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: check that STDOUT write works
4 */
5 #include <errno.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <fcntl.h>
11
12 #include "helpers.h"
13 #include "liburing.h"
14
test_pipe_io_fixed(struct io_uring * ring)15 static int test_pipe_io_fixed(struct io_uring *ring)
16 {
17 const char str[] = "This is a fixed pipe test\n";
18 struct io_uring_cqe *cqe;
19 struct io_uring_sqe *sqe;
20 struct iovec vecs[2];
21 char buffer[128];
22 int i, ret, fds[2];
23
24 t_posix_memalign(&vecs[0].iov_base, 4096, 4096);
25 memcpy(vecs[0].iov_base, str, strlen(str));
26 vecs[0].iov_len = strlen(str);
27
28 if (pipe(fds) < 0) {
29 perror("pipe");
30 return 1;
31 }
32
33 ret = io_uring_register_buffers(ring, vecs, 1);
34 if (ret) {
35 fprintf(stderr, "Failed to register buffers: %d\n", ret);
36 return 1;
37 }
38
39 sqe = io_uring_get_sqe(ring);
40 if (!sqe) {
41 fprintf(stderr, "get sqe failed\n");
42 goto err;
43 }
44 io_uring_prep_write_fixed(sqe, fds[1], vecs[0].iov_base,
45 vecs[0].iov_len, 0, 0);
46 sqe->user_data = 1;
47
48 sqe = io_uring_get_sqe(ring);
49 if (!sqe) {
50 fprintf(stderr, "get sqe failed\n");
51 goto err;
52 }
53 vecs[1].iov_base = buffer;
54 vecs[1].iov_len = sizeof(buffer);
55 io_uring_prep_readv(sqe, fds[0], &vecs[1], 1, 0);
56 sqe->user_data = 2;
57
58 ret = io_uring_submit(ring);
59 if (ret < 0) {
60 fprintf(stderr, "sqe submit failed: %d\n", ret);
61 goto err;
62 } else if (ret != 2) {
63 fprintf(stderr, "Submitted only %d\n", ret);
64 goto err;
65 }
66
67 for (i = 0; i < 2; i++) {
68 ret = io_uring_wait_cqe(ring, &cqe);
69 if (ret < 0) {
70 fprintf(stderr, "wait completion %d\n", ret);
71 goto err;
72 }
73 if (cqe->res < 0) {
74 fprintf(stderr, "I/O write error on %lu: %s\n",
75 (unsigned long) cqe->user_data,
76 strerror(-cqe->res));
77 goto err;
78 }
79 if (cqe->res != strlen(str)) {
80 fprintf(stderr, "Got %d bytes, wanted %d on %lu\n",
81 cqe->res, (int)strlen(str),
82 (unsigned long) cqe->user_data);
83 goto err;
84 }
85 if (cqe->user_data == 2 && memcmp(str, buffer, strlen(str))) {
86 fprintf(stderr, "read data mismatch\n");
87 goto err;
88 }
89 io_uring_cqe_seen(ring, cqe);
90 }
91 io_uring_unregister_buffers(ring);
92 free(vecs[0].iov_base);
93 return 0;
94 err:
95 return 1;
96 }
97
test_stdout_io_fixed(struct io_uring * ring)98 static int test_stdout_io_fixed(struct io_uring *ring)
99 {
100 const char str[] = "This is a fixed pipe test\n";
101 struct io_uring_cqe *cqe;
102 struct io_uring_sqe *sqe;
103 struct iovec vecs;
104 int ret;
105
106 t_posix_memalign(&vecs.iov_base, 4096, 4096);
107 memcpy(vecs.iov_base, str, strlen(str));
108 vecs.iov_len = strlen(str);
109
110 ret = io_uring_register_buffers(ring, &vecs, 1);
111 if (ret) {
112 fprintf(stderr, "Failed to register buffers: %d\n", ret);
113 return 1;
114 }
115
116 sqe = io_uring_get_sqe(ring);
117 if (!sqe) {
118 fprintf(stderr, "get sqe failed\n");
119 goto err;
120 }
121 io_uring_prep_write_fixed(sqe, STDOUT_FILENO, vecs.iov_base, vecs.iov_len, 0, 0);
122
123 ret = io_uring_submit(ring);
124 if (ret < 0) {
125 fprintf(stderr, "sqe submit failed: %d\n", ret);
126 goto err;
127 } else if (ret < 1) {
128 fprintf(stderr, "Submitted only %d\n", ret);
129 goto err;
130 }
131
132 ret = io_uring_wait_cqe(ring, &cqe);
133 if (ret < 0) {
134 fprintf(stderr, "wait completion %d\n", ret);
135 goto err;
136 }
137 if (cqe->res < 0) {
138 fprintf(stderr, "STDOUT write error: %s\n", strerror(-cqe->res));
139 goto err;
140 }
141 if (cqe->res != vecs.iov_len) {
142 fprintf(stderr, "Got %d write, wanted %d\n", cqe->res, (int)vecs.iov_len);
143 goto err;
144 }
145 io_uring_cqe_seen(ring, cqe);
146 io_uring_unregister_buffers(ring);
147 free(vecs.iov_base);
148 return 0;
149 err:
150 return 1;
151 }
152
test_stdout_io(struct io_uring * ring)153 static int test_stdout_io(struct io_uring *ring)
154 {
155 struct io_uring_cqe *cqe;
156 struct io_uring_sqe *sqe;
157 struct iovec vecs;
158 int ret;
159
160 vecs.iov_base = "This is a pipe test\n";
161 vecs.iov_len = strlen(vecs.iov_base);
162
163 sqe = io_uring_get_sqe(ring);
164 if (!sqe) {
165 fprintf(stderr, "get sqe failed\n");
166 goto err;
167 }
168 io_uring_prep_writev(sqe, STDOUT_FILENO, &vecs, 1, 0);
169
170 ret = io_uring_submit(ring);
171 if (ret < 0) {
172 fprintf(stderr, "sqe submit failed: %d\n", ret);
173 goto err;
174 } else if (ret < 1) {
175 fprintf(stderr, "Submitted only %d\n", ret);
176 goto err;
177 }
178
179 ret = io_uring_wait_cqe(ring, &cqe);
180 if (ret < 0) {
181 fprintf(stderr, "wait completion %d\n", ret);
182 goto err;
183 }
184 if (cqe->res < 0) {
185 fprintf(stderr, "STDOUT write error: %s\n",
186 strerror(-cqe->res));
187 goto err;
188 }
189 if (cqe->res != vecs.iov_len) {
190 fprintf(stderr, "Got %d write, wanted %d\n", cqe->res,
191 (int)vecs.iov_len);
192 goto err;
193 }
194 io_uring_cqe_seen(ring, cqe);
195
196 return 0;
197 err:
198 return 1;
199 }
200
main(int argc,char * argv[])201 int main(int argc, char *argv[])
202 {
203 struct io_uring ring;
204 int ret;
205
206 if (argc > 1)
207 return 0;
208
209 ret = io_uring_queue_init(8, &ring, 0);
210 if (ret) {
211 fprintf(stderr, "ring setup failed\n");
212 return 1;
213 }
214
215 ret = test_stdout_io(&ring);
216 if (ret) {
217 fprintf(stderr, "test_pipe_io failed\n");
218 return ret;
219 }
220
221 ret = test_stdout_io_fixed(&ring);
222 if (ret) {
223 fprintf(stderr, "test_pipe_io_fixed failed\n");
224 return ret;
225 }
226
227 ret = test_pipe_io_fixed(&ring);
228 if (ret) {
229 fprintf(stderr, "test_pipe_io_fixed failed\n");
230 return ret;
231 }
232
233 return 0;
234 }
235