xref: /aosp_15_r20/external/liburing/test/io_uring_enter.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
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