blob: 698e37c81774cd1f9045ffd26e62bfe5065b6319 [file] [log] [blame]
Jens Axboee5024352020-02-11 20:34:12 -07001/* SPDX-License-Identifier: MIT */
Jeff Moyer765ba232019-03-04 17:35:49 -05002/*
3 * io_uring_enter.c
4 *
5 * Description: Unit tests for the io_uring_enter system call.
6 *
7 * Copyright 2019, Red Hat, Inc.
8 * Author: Jeff Moyer <jmoyer@redhat.com>
9 */
10#include <stdio.h>
11#include <fcntl.h>
12#include <string.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <errno.h>
16#include <sys/sysinfo.h>
17#include <poll.h>
18#include <assert.h>
19#include <sys/uio.h>
20#include <sys/mman.h>
21#include <linux/mman.h>
22#include <sys/time.h>
23#include <sys/resource.h>
24#include <limits.h>
25#include <sys/time.h>
Zhiqiang Liu97499812021-02-21 22:58:12 +080026
27#include "helpers.h"
Stefan Hajnoczic31c7ec2019-07-24 09:24:50 +010028#include "liburing.h"
29#include "liburing/barrier.h"
Jens Axboe96144ea2019-12-01 11:21:39 -070030#include "../src/syscall.h"
Jeff Moyer765ba232019-03-04 17:35:49 -050031
32#define IORING_MAX_ENTRIES 4096
33
34int
35expect_failed_submit(struct io_uring *ring, int error)
36{
37 int ret;
38
39 ret = io_uring_submit(ring);
40 if (ret == 1) {
41 printf("expected failure, but io_uring_submit succeeded.\n");
42 return 1;
43 }
44
45 if (errno != error) {
46 printf("expected %d, got %d\n", error, errno);
47 return 1;
48 }
49
50 return 0;
51}
52
53int
54expect_fail(int fd, unsigned int to_submit, unsigned int min_complete,
55 unsigned int flags, sigset_t *sig, int error)
56{
57 int ret;
58
Jens Axboe96144ea2019-12-01 11:21:39 -070059 ret = __sys_io_uring_enter(fd, to_submit, min_complete, flags, sig);
Jeff Moyer765ba232019-03-04 17:35:49 -050060 if (ret != -1) {
61 printf("expected %s, but call succeeded\n", strerror(error));
62 return 1;
63 }
64
65 if (errno != error) {
66 printf("expected %d, got %d\n", error, errno);
67 return 1;
68 }
69
70 return 0;
71}
72
73int
74try_io_uring_enter(int fd, unsigned int to_submit, unsigned int min_complete,
75 unsigned int flags, sigset_t *sig, int expect, int error)
76{
77 int ret;
78
79 printf("io_uring_enter(%d, %u, %u, %u, %p)\n", fd, to_submit,
80 min_complete, flags, sig);
81
82 if (expect == -1)
83 return expect_fail(fd, to_submit, min_complete,
84 flags, sig, error);
85
Jens Axboe96144ea2019-12-01 11:21:39 -070086 ret = __sys_io_uring_enter(fd, to_submit, min_complete, flags, sig);
Jeff Moyer765ba232019-03-04 17:35:49 -050087 if (ret != expect) {
88 printf("Expected %d, got %d\n", expect, errno);
89 return 1;
90 }
91
92 return 0;
93}
94
95/*
96 * prep a read I/O. index is treated like a block number.
97 */
98int
Jens Axboeca50c1f2019-09-10 17:57:28 -060099setup_file(char *template, off_t len)
Jeff Moyer765ba232019-03-04 17:35:49 -0500100{
101 int fd, ret;
Jeff Moyer765ba232019-03-04 17:35:49 -0500102 char buf[4096];
103
104 fd = mkstemp(template);
105 if (fd < 0) {
106 perror("mkstemp");
107 exit(1);
108 }
109 ret = ftruncate(fd, len);
110 if (ret < 0) {
111 perror("ftruncate");
112 exit(1);
113 }
114
115 ret = read(fd, buf, 4096);
116 if (ret != 4096) {
117 printf("read returned %d, expected 4096\n", ret);
118 exit(1);
119 }
120
121 return fd;
122}
123
124void
125io_prep_read(struct io_uring_sqe *sqe, int fd, off_t offset, size_t len)
126{
127 struct iovec *iov;
128
Zhiqiang Liu97499812021-02-21 22:58:12 +0800129 iov = io_uring_malloc(sizeof(*iov));
Jeff Moyer765ba232019-03-04 17:35:49 -0500130 assert(iov);
131
Zhiqiang Liu97499812021-02-21 22:58:12 +0800132 iov->iov_base = io_uring_malloc(len);
Jeff Moyer765ba232019-03-04 17:35:49 -0500133 assert(iov->iov_base);
134 iov->iov_len = len;
135
136 io_uring_prep_readv(sqe, fd, iov, 1, offset);
137 io_uring_sqe_set_data(sqe, iov); // free on completion
138}
139
140void
141reap_events(struct io_uring *ring, unsigned nr)
142{
143 int ret;
144 unsigned left = nr;
145 struct io_uring_cqe *cqe;
146 struct iovec *iov;
147 struct timeval start, now, elapsed;
148
149 printf("Reaping %u I/Os\n", nr);
150 gettimeofday(&start, NULL);
151 while (left) {
Jens Axboe39e0ebd2019-04-18 08:32:06 -0600152 ret = io_uring_wait_cqe(ring, &cqe);
Jeff Moyer765ba232019-03-04 17:35:49 -0500153 if (ret < 0) {
Jens Axboe39e0ebd2019-04-18 08:32:06 -0600154 printf("io_uring_wait_cqe returned %d\n", ret);
Jeff Moyer765ba232019-03-04 17:35:49 -0500155 printf("expected success\n");
156 exit(1);
157 }
158 if (cqe->res != 4096)
159 printf("cqe->res: %d, expected 4096\n", cqe->res);
Jens Axboedb11f112019-04-07 18:36:43 -0600160 iov = io_uring_cqe_get_data(cqe);
Jeff Moyer765ba232019-03-04 17:35:49 -0500161 free(iov->iov_base);
162 free(iov);
163 left--;
Jens Axboe76b61eb2019-04-17 09:25:32 -0600164 io_uring_cqe_seen(ring, cqe);
Jeff Moyer765ba232019-03-04 17:35:49 -0500165
166 gettimeofday(&now, NULL);
167 timersub(&now, &start, &elapsed);
168 if (elapsed.tv_sec > 10) {
169 printf("Timed out waiting for I/Os to complete.\n");
170 printf("%u expected, %u completed\n", nr, left);
171 break;
172 }
173 }
174}
175
176void
177submit_io(struct io_uring *ring, unsigned nr)
178{
179 int fd, ret;
180 off_t file_len;
181 unsigned i;
Jens Axboeca50c1f2019-09-10 17:57:28 -0600182 static char template[32] = "/tmp/io_uring_enter-test.XXXXXX";
Jeff Moyer765ba232019-03-04 17:35:49 -0500183 struct io_uring_sqe *sqe;
184
185 printf("Allocating %u sqes\n", nr);
186 file_len = nr * 4096;
Jens Axboeca50c1f2019-09-10 17:57:28 -0600187 fd = setup_file(template, file_len);
Jeff Moyer765ba232019-03-04 17:35:49 -0500188 for (i = 0; i < nr; i++) {
189 /* allocate an sqe */
190 sqe = io_uring_get_sqe(ring);
191 /* fill it in */
192 io_prep_read(sqe, fd, i * 4096, 4096);
193 }
194
195 /* submit the I/Os */
196 printf("Submitting %u I/Os\n", nr);
197 ret = io_uring_submit(ring);
Jens Axboeca50c1f2019-09-10 17:57:28 -0600198 unlink(template);
Jeff Moyer765ba232019-03-04 17:35:49 -0500199 if (ret < 0) {
200 perror("io_uring_enter");
201 exit(1);
202 }
203 printf("Done\n");
204}
205
206int
207main(int argc, char **argv)
208{
209 int ret;
210 unsigned int status = 0;
211 struct io_uring ring;
212 struct io_uring_sq *sq = &ring.sq;
213 unsigned ktail, mask, index;
214 unsigned sq_entries;
215 unsigned completed, dropped;
216
Jens Axboea2141fc2020-05-19 17:36:19 -0600217 if (argc > 1)
218 return 0;
219
Jeff Moyer765ba232019-03-04 17:35:49 -0500220 ret = io_uring_queue_init(IORING_MAX_ENTRIES, &ring, 0);
221 if (ret < 0) {
222 perror("io_uring_queue_init");
223 exit(1);
224 }
225 mask = *sq->kring_mask;
226
227 /* invalid flags */
228 status |= try_io_uring_enter(ring.ring_fd, 1, 0, ~0U, NULL, -1, EINVAL);
229
230 /* invalid fd, EBADF */
231 status |= try_io_uring_enter(-1, 0, 0, 0, NULL, -1, EBADF);
232
233 /* valid, non-ring fd, EOPNOTSUPP */
234 status |= try_io_uring_enter(0, 0, 0, 0, NULL, -1, EOPNOTSUPP);
235
236 /* to_submit: 0, flags: 0; should get back 0. */
237 status |= try_io_uring_enter(ring.ring_fd, 1, 0, 0, NULL, 0, 0);
238
239 /* fill the sq ring */
240 sq_entries = *ring.sq.kring_entries;
241 submit_io(&ring, sq_entries);
242 printf("Waiting for %u events\n", sq_entries);
Jens Axboe96144ea2019-12-01 11:21:39 -0700243 ret = __sys_io_uring_enter(ring.ring_fd, 0, sq_entries,
244 IORING_ENTER_GETEVENTS, NULL);
Jeff Moyer765ba232019-03-04 17:35:49 -0500245 if (ret < 0) {
246 perror("io_uring_enter");
247 status = 1;
248 } else {
249 /*
250 * This is a non-IOPOLL ring, which means that io_uring_enter
251 * should not return until min_complete events are available
252 * in the completion queue.
253 */
254 completed = *ring.cq.ktail - *ring.cq.khead;
255 if (completed != sq_entries) {
256 printf("Submitted %u I/Os, but only got %u completions\n",
257 sq_entries, completed);
258 status = 1;
259 }
260 reap_events(&ring, sq_entries);
261 }
262
263 /*
264 * Add an invalid index to the submission queue. This should
265 * result in the dropped counter increasing.
266 */
267 printf("Submitting invalid sqe index.\n");
268 index = *sq->kring_entries + 1; // invalid index
269 dropped = *sq->kdropped;
270 ktail = *sq->ktail;
271 sq->array[ktail & mask] = index;
272 ++ktail;
Bart Van Asscheecefd792019-07-01 14:42:32 -0700273 /*
274 * Ensure that the kernel sees the SQE update before it sees the tail
275 * update.
276 */
Julia Suvorova552c6a02019-08-19 08:45:28 -0600277 io_uring_smp_store_release(sq->ktail, ktail);
Jeff Moyer765ba232019-03-04 17:35:49 -0500278
Jens Axboe96144ea2019-12-01 11:21:39 -0700279 ret = __sys_io_uring_enter(ring.ring_fd, 1, 0, 0, NULL);
Jeff Moyer765ba232019-03-04 17:35:49 -0500280 /* now check to see if our sqe was dropped */
281 if (*sq->kdropped == dropped) {
282 printf("dropped counter did not increase\n");
283 status = 1;
284 }
285
286 if (!status) {
287 printf("PASS\n");
288 return 0;
289 }
290
291 printf("FAIL\n");
292 return -1;
293}