1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker * io_uring_enter.c
4*25da2beaSAndroid Build Coastguard Worker *
5*25da2beaSAndroid Build Coastguard Worker * Description: Unit tests for the io_uring_enter system call.
6*25da2beaSAndroid Build Coastguard Worker *
7*25da2beaSAndroid Build Coastguard Worker * Copyright 2019, Red Hat, Inc.
8*25da2beaSAndroid Build Coastguard Worker * Author: Jeff Moyer <[email protected]>
9*25da2beaSAndroid Build Coastguard Worker */
10*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
11*25da2beaSAndroid Build Coastguard Worker #include <fcntl.h>
12*25da2beaSAndroid Build Coastguard Worker #include <string.h>
13*25da2beaSAndroid Build Coastguard Worker #include <stdlib.h>
14*25da2beaSAndroid Build Coastguard Worker #include <unistd.h>
15*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
16*25da2beaSAndroid Build Coastguard Worker #include <sys/sysinfo.h>
17*25da2beaSAndroid Build Coastguard Worker #include <poll.h>
18*25da2beaSAndroid Build Coastguard Worker #include <assert.h>
19*25da2beaSAndroid Build Coastguard Worker #include <sys/uio.h>
20*25da2beaSAndroid Build Coastguard Worker #include <sys/mman.h>
21*25da2beaSAndroid Build Coastguard Worker #include <linux/mman.h>
22*25da2beaSAndroid Build Coastguard Worker #include <sys/time.h>
23*25da2beaSAndroid Build Coastguard Worker #include <sys/resource.h>
24*25da2beaSAndroid Build Coastguard Worker #include <limits.h>
25*25da2beaSAndroid Build Coastguard Worker #include <sys/time.h>
26*25da2beaSAndroid Build Coastguard Worker
27*25da2beaSAndroid Build Coastguard Worker #include "helpers.h"
28*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
29*25da2beaSAndroid Build Coastguard Worker #include "liburing/barrier.h"
30*25da2beaSAndroid Build Coastguard Worker #include "../src/syscall.h"
31*25da2beaSAndroid Build Coastguard Worker
32*25da2beaSAndroid Build Coastguard Worker #define IORING_MAX_ENTRIES 4096
33*25da2beaSAndroid Build Coastguard Worker #define IORING_MAX_ENTRIES_FALLBACK 128
34*25da2beaSAndroid Build Coastguard Worker
expect_fail(int fd,unsigned int to_submit,unsigned int min_complete,unsigned int flags,sigset_t * sig,int error)35*25da2beaSAndroid Build Coastguard Worker static int expect_fail(int fd, unsigned int to_submit,
36*25da2beaSAndroid Build Coastguard Worker unsigned int min_complete, unsigned int flags,
37*25da2beaSAndroid Build Coastguard Worker sigset_t *sig, int error)
38*25da2beaSAndroid Build Coastguard Worker {
39*25da2beaSAndroid Build Coastguard Worker int ret;
40*25da2beaSAndroid Build Coastguard Worker
41*25da2beaSAndroid Build Coastguard Worker ret = __sys_io_uring_enter(fd, to_submit, min_complete, flags, sig);
42*25da2beaSAndroid Build Coastguard Worker if (ret != -1) {
43*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "expected %s, but call succeeded\n", strerror(error));
44*25da2beaSAndroid Build Coastguard Worker return 1;
45*25da2beaSAndroid Build Coastguard Worker }
46*25da2beaSAndroid Build Coastguard Worker
47*25da2beaSAndroid Build Coastguard Worker if (errno != error) {
48*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "expected %d, got %d\n", error, errno);
49*25da2beaSAndroid Build Coastguard Worker return 1;
50*25da2beaSAndroid Build Coastguard Worker }
51*25da2beaSAndroid Build Coastguard Worker
52*25da2beaSAndroid Build Coastguard Worker return 0;
53*25da2beaSAndroid Build Coastguard Worker }
54*25da2beaSAndroid Build Coastguard Worker
try_io_uring_enter(int fd,unsigned int to_submit,unsigned int min_complete,unsigned int flags,sigset_t * sig,int expect,int error)55*25da2beaSAndroid Build Coastguard Worker static int try_io_uring_enter(int fd, unsigned int to_submit,
56*25da2beaSAndroid Build Coastguard Worker unsigned int min_complete, unsigned int flags,
57*25da2beaSAndroid Build Coastguard Worker sigset_t *sig, int expect, int error)
58*25da2beaSAndroid Build Coastguard Worker {
59*25da2beaSAndroid Build Coastguard Worker int ret;
60*25da2beaSAndroid Build Coastguard Worker
61*25da2beaSAndroid Build Coastguard Worker if (expect == -1)
62*25da2beaSAndroid Build Coastguard Worker return expect_fail(fd, to_submit, min_complete,
63*25da2beaSAndroid Build Coastguard Worker flags, sig, error);
64*25da2beaSAndroid Build Coastguard Worker
65*25da2beaSAndroid Build Coastguard Worker ret = __sys_io_uring_enter(fd, to_submit, min_complete, flags, sig);
66*25da2beaSAndroid Build Coastguard Worker if (ret != expect) {
67*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "Expected %d, got %d\n", expect, errno);
68*25da2beaSAndroid Build Coastguard Worker return 1;
69*25da2beaSAndroid Build Coastguard Worker }
70*25da2beaSAndroid Build Coastguard Worker
71*25da2beaSAndroid Build Coastguard Worker return 0;
72*25da2beaSAndroid Build Coastguard Worker }
73*25da2beaSAndroid Build Coastguard Worker
74*25da2beaSAndroid Build Coastguard Worker /*
75*25da2beaSAndroid Build Coastguard Worker * prep a read I/O. index is treated like a block number.
76*25da2beaSAndroid Build Coastguard Worker */
setup_file(char * template,off_t len)77*25da2beaSAndroid Build Coastguard Worker static int setup_file(char *template, off_t len)
78*25da2beaSAndroid Build Coastguard Worker {
79*25da2beaSAndroid Build Coastguard Worker int fd, ret;
80*25da2beaSAndroid Build Coastguard Worker char buf[4096];
81*25da2beaSAndroid Build Coastguard Worker
82*25da2beaSAndroid Build Coastguard Worker fd = mkstemp(template);
83*25da2beaSAndroid Build Coastguard Worker if (fd < 0) {
84*25da2beaSAndroid Build Coastguard Worker perror("mkstemp");
85*25da2beaSAndroid Build Coastguard Worker exit(1);
86*25da2beaSAndroid Build Coastguard Worker }
87*25da2beaSAndroid Build Coastguard Worker ret = ftruncate(fd, len);
88*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
89*25da2beaSAndroid Build Coastguard Worker perror("ftruncate");
90*25da2beaSAndroid Build Coastguard Worker exit(1);
91*25da2beaSAndroid Build Coastguard Worker }
92*25da2beaSAndroid Build Coastguard Worker
93*25da2beaSAndroid Build Coastguard Worker ret = read(fd, buf, 4096);
94*25da2beaSAndroid Build Coastguard Worker if (ret != 4096) {
95*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "read returned %d, expected 4096\n", ret);
96*25da2beaSAndroid Build Coastguard Worker exit(1);
97*25da2beaSAndroid Build Coastguard Worker }
98*25da2beaSAndroid Build Coastguard Worker
99*25da2beaSAndroid Build Coastguard Worker return fd;
100*25da2beaSAndroid Build Coastguard Worker }
101*25da2beaSAndroid Build Coastguard Worker
io_prep_read(struct io_uring_sqe * sqe,int fd,off_t offset,size_t len)102*25da2beaSAndroid Build Coastguard Worker static void io_prep_read(struct io_uring_sqe *sqe, int fd, off_t offset,
103*25da2beaSAndroid Build Coastguard Worker size_t len)
104*25da2beaSAndroid Build Coastguard Worker {
105*25da2beaSAndroid Build Coastguard Worker struct iovec *iov;
106*25da2beaSAndroid Build Coastguard Worker
107*25da2beaSAndroid Build Coastguard Worker iov = t_malloc(sizeof(*iov));
108*25da2beaSAndroid Build Coastguard Worker assert(iov);
109*25da2beaSAndroid Build Coastguard Worker
110*25da2beaSAndroid Build Coastguard Worker iov->iov_base = t_malloc(len);
111*25da2beaSAndroid Build Coastguard Worker assert(iov->iov_base);
112*25da2beaSAndroid Build Coastguard Worker iov->iov_len = len;
113*25da2beaSAndroid Build Coastguard Worker
114*25da2beaSAndroid Build Coastguard Worker io_uring_prep_readv(sqe, fd, iov, 1, offset);
115*25da2beaSAndroid Build Coastguard Worker io_uring_sqe_set_data(sqe, iov); // free on completion
116*25da2beaSAndroid Build Coastguard Worker }
117*25da2beaSAndroid Build Coastguard Worker
reap_events(struct io_uring * ring,unsigned nr)118*25da2beaSAndroid Build Coastguard Worker static void reap_events(struct io_uring *ring, unsigned nr)
119*25da2beaSAndroid Build Coastguard Worker {
120*25da2beaSAndroid Build Coastguard Worker int ret;
121*25da2beaSAndroid Build Coastguard Worker unsigned left = nr;
122*25da2beaSAndroid Build Coastguard Worker struct io_uring_cqe *cqe;
123*25da2beaSAndroid Build Coastguard Worker struct iovec *iov;
124*25da2beaSAndroid Build Coastguard Worker struct timeval start, now, elapsed;
125*25da2beaSAndroid Build Coastguard Worker
126*25da2beaSAndroid Build Coastguard Worker gettimeofday(&start, NULL);
127*25da2beaSAndroid Build Coastguard Worker while (left) {
128*25da2beaSAndroid Build Coastguard Worker ret = io_uring_wait_cqe(ring, &cqe);
129*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
130*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "io_uring_wait_cqe returned %d\n", ret);
131*25da2beaSAndroid Build Coastguard Worker exit(1);
132*25da2beaSAndroid Build Coastguard Worker }
133*25da2beaSAndroid Build Coastguard Worker if (cqe->res != 4096)
134*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "cqe->res: %d, expected 4096\n", cqe->res);
135*25da2beaSAndroid Build Coastguard Worker iov = io_uring_cqe_get_data(cqe);
136*25da2beaSAndroid Build Coastguard Worker free(iov->iov_base);
137*25da2beaSAndroid Build Coastguard Worker free(iov);
138*25da2beaSAndroid Build Coastguard Worker left--;
139*25da2beaSAndroid Build Coastguard Worker io_uring_cqe_seen(ring, cqe);
140*25da2beaSAndroid Build Coastguard Worker
141*25da2beaSAndroid Build Coastguard Worker gettimeofday(&now, NULL);
142*25da2beaSAndroid Build Coastguard Worker timersub(&now, &start, &elapsed);
143*25da2beaSAndroid Build Coastguard Worker if (elapsed.tv_sec > 10) {
144*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "Timed out waiting for I/Os to complete.\n");
145*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "%u expected, %u completed\n", nr, left);
146*25da2beaSAndroid Build Coastguard Worker break;
147*25da2beaSAndroid Build Coastguard Worker }
148*25da2beaSAndroid Build Coastguard Worker }
149*25da2beaSAndroid Build Coastguard Worker }
150*25da2beaSAndroid Build Coastguard Worker
submit_io(struct io_uring * ring,unsigned nr)151*25da2beaSAndroid Build Coastguard Worker static void submit_io(struct io_uring *ring, unsigned nr)
152*25da2beaSAndroid Build Coastguard Worker {
153*25da2beaSAndroid Build Coastguard Worker int fd, ret;
154*25da2beaSAndroid Build Coastguard Worker off_t file_len;
155*25da2beaSAndroid Build Coastguard Worker unsigned i;
156*25da2beaSAndroid Build Coastguard Worker static char template[32] = "/tmp/io_uring_enter-test.XXXXXX";
157*25da2beaSAndroid Build Coastguard Worker struct io_uring_sqe *sqe;
158*25da2beaSAndroid Build Coastguard Worker
159*25da2beaSAndroid Build Coastguard Worker file_len = nr * 4096;
160*25da2beaSAndroid Build Coastguard Worker fd = setup_file(template, file_len);
161*25da2beaSAndroid Build Coastguard Worker for (i = 0; i < nr; i++) {
162*25da2beaSAndroid Build Coastguard Worker /* allocate an sqe */
163*25da2beaSAndroid Build Coastguard Worker sqe = io_uring_get_sqe(ring);
164*25da2beaSAndroid Build Coastguard Worker /* fill it in */
165*25da2beaSAndroid Build Coastguard Worker io_prep_read(sqe, fd, i * 4096, 4096);
166*25da2beaSAndroid Build Coastguard Worker }
167*25da2beaSAndroid Build Coastguard Worker
168*25da2beaSAndroid Build Coastguard Worker /* submit the I/Os */
169*25da2beaSAndroid Build Coastguard Worker ret = io_uring_submit(ring);
170*25da2beaSAndroid Build Coastguard Worker unlink(template);
171*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
172*25da2beaSAndroid Build Coastguard Worker perror("io_uring_enter");
173*25da2beaSAndroid Build Coastguard Worker exit(1);
174*25da2beaSAndroid Build Coastguard Worker }
175*25da2beaSAndroid Build Coastguard Worker }
176*25da2beaSAndroid Build Coastguard Worker
main(int argc,char ** argv)177*25da2beaSAndroid Build Coastguard Worker int main(int argc, char **argv)
178*25da2beaSAndroid Build Coastguard Worker {
179*25da2beaSAndroid Build Coastguard Worker int ret;
180*25da2beaSAndroid Build Coastguard Worker unsigned int status = 0;
181*25da2beaSAndroid Build Coastguard Worker struct io_uring ring;
182*25da2beaSAndroid Build Coastguard Worker struct io_uring_sq *sq = &ring.sq;
183*25da2beaSAndroid Build Coastguard Worker unsigned ktail, mask, index;
184*25da2beaSAndroid Build Coastguard Worker unsigned sq_entries;
185*25da2beaSAndroid Build Coastguard Worker unsigned completed, dropped;
186*25da2beaSAndroid Build Coastguard Worker
187*25da2beaSAndroid Build Coastguard Worker if (argc > 1)
188*25da2beaSAndroid Build Coastguard Worker return 0;
189*25da2beaSAndroid Build Coastguard Worker
190*25da2beaSAndroid Build Coastguard Worker ret = io_uring_queue_init(IORING_MAX_ENTRIES, &ring, 0);
191*25da2beaSAndroid Build Coastguard Worker if (ret == -ENOMEM)
192*25da2beaSAndroid Build Coastguard Worker ret = io_uring_queue_init(IORING_MAX_ENTRIES_FALLBACK, &ring, 0);
193*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
194*25da2beaSAndroid Build Coastguard Worker perror("io_uring_queue_init");
195*25da2beaSAndroid Build Coastguard Worker exit(1);
196*25da2beaSAndroid Build Coastguard Worker }
197*25da2beaSAndroid Build Coastguard Worker mask = *sq->kring_mask;
198*25da2beaSAndroid Build Coastguard Worker
199*25da2beaSAndroid Build Coastguard Worker /* invalid flags */
200*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_enter(ring.ring_fd, 1, 0, ~0U, NULL, -1, EINVAL);
201*25da2beaSAndroid Build Coastguard Worker
202*25da2beaSAndroid Build Coastguard Worker /* invalid fd, EBADF */
203*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_enter(-1, 0, 0, 0, NULL, -1, EBADF);
204*25da2beaSAndroid Build Coastguard Worker
205*25da2beaSAndroid Build Coastguard Worker /* valid, non-ring fd, EOPNOTSUPP */
206*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_enter(0, 0, 0, 0, NULL, -1, EOPNOTSUPP);
207*25da2beaSAndroid Build Coastguard Worker
208*25da2beaSAndroid Build Coastguard Worker /* to_submit: 0, flags: 0; should get back 0. */
209*25da2beaSAndroid Build Coastguard Worker status |= try_io_uring_enter(ring.ring_fd, 0, 0, 0, NULL, 0, 0);
210*25da2beaSAndroid Build Coastguard Worker
211*25da2beaSAndroid Build Coastguard Worker /* fill the sq ring */
212*25da2beaSAndroid Build Coastguard Worker sq_entries = *ring.sq.kring_entries;
213*25da2beaSAndroid Build Coastguard Worker submit_io(&ring, sq_entries);
214*25da2beaSAndroid Build Coastguard Worker ret = __sys_io_uring_enter(ring.ring_fd, 0, sq_entries,
215*25da2beaSAndroid Build Coastguard Worker IORING_ENTER_GETEVENTS, NULL);
216*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
217*25da2beaSAndroid Build Coastguard Worker perror("io_uring_enter");
218*25da2beaSAndroid Build Coastguard Worker status = 1;
219*25da2beaSAndroid Build Coastguard Worker } else {
220*25da2beaSAndroid Build Coastguard Worker /*
221*25da2beaSAndroid Build Coastguard Worker * This is a non-IOPOLL ring, which means that io_uring_enter
222*25da2beaSAndroid Build Coastguard Worker * should not return until min_complete events are available
223*25da2beaSAndroid Build Coastguard Worker * in the completion queue.
224*25da2beaSAndroid Build Coastguard Worker */
225*25da2beaSAndroid Build Coastguard Worker completed = *ring.cq.ktail - *ring.cq.khead;
226*25da2beaSAndroid Build Coastguard Worker if (completed != sq_entries) {
227*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "Submitted %u I/Os, but only got %u completions\n",
228*25da2beaSAndroid Build Coastguard Worker sq_entries, completed);
229*25da2beaSAndroid Build Coastguard Worker status = 1;
230*25da2beaSAndroid Build Coastguard Worker }
231*25da2beaSAndroid Build Coastguard Worker reap_events(&ring, sq_entries);
232*25da2beaSAndroid Build Coastguard Worker }
233*25da2beaSAndroid Build Coastguard Worker
234*25da2beaSAndroid Build Coastguard Worker /*
235*25da2beaSAndroid Build Coastguard Worker * Add an invalid index to the submission queue. This should
236*25da2beaSAndroid Build Coastguard Worker * result in the dropped counter increasing.
237*25da2beaSAndroid Build Coastguard Worker */
238*25da2beaSAndroid Build Coastguard Worker index = *sq->kring_entries + 1; // invalid index
239*25da2beaSAndroid Build Coastguard Worker dropped = *sq->kdropped;
240*25da2beaSAndroid Build Coastguard Worker ktail = *sq->ktail;
241*25da2beaSAndroid Build Coastguard Worker sq->array[ktail & mask] = index;
242*25da2beaSAndroid Build Coastguard Worker ++ktail;
243*25da2beaSAndroid Build Coastguard Worker /*
244*25da2beaSAndroid Build Coastguard Worker * Ensure that the kernel sees the SQE update before it sees the tail
245*25da2beaSAndroid Build Coastguard Worker * update.
246*25da2beaSAndroid Build Coastguard Worker */
247*25da2beaSAndroid Build Coastguard Worker io_uring_smp_store_release(sq->ktail, ktail);
248*25da2beaSAndroid Build Coastguard Worker
249*25da2beaSAndroid Build Coastguard Worker ret = __sys_io_uring_enter(ring.ring_fd, 1, 0, 0, NULL);
250*25da2beaSAndroid Build Coastguard Worker /* now check to see if our sqe was dropped */
251*25da2beaSAndroid Build Coastguard Worker if (*sq->kdropped == dropped) {
252*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "dropped counter did not increase\n");
253*25da2beaSAndroid Build Coastguard Worker status = 1;
254*25da2beaSAndroid Build Coastguard Worker }
255*25da2beaSAndroid Build Coastguard Worker
256*25da2beaSAndroid Build Coastguard Worker if (!status)
257*25da2beaSAndroid Build Coastguard Worker return 0;
258*25da2beaSAndroid Build Coastguard Worker
259*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "FAIL\n");
260*25da2beaSAndroid Build Coastguard Worker return -1;
261*25da2beaSAndroid Build Coastguard Worker }
262