xref: /aosp_15_r20/external/liburing/test/timeout-overflow.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker  * Description: run timeout overflow test
4*25da2beaSAndroid Build Coastguard Worker  *
5*25da2beaSAndroid Build Coastguard Worker  */
6*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
7*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
8*25da2beaSAndroid Build Coastguard Worker #include <limits.h>
9*25da2beaSAndroid Build Coastguard Worker #include <string.h>
10*25da2beaSAndroid Build Coastguard Worker #include <sys/time.h>
11*25da2beaSAndroid Build Coastguard Worker 
12*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
13*25da2beaSAndroid Build Coastguard Worker 
14*25da2beaSAndroid Build Coastguard Worker #define TIMEOUT_MSEC	200
15*25da2beaSAndroid Build Coastguard Worker static int not_supported;
16*25da2beaSAndroid Build Coastguard Worker 
msec_to_ts(struct __kernel_timespec * ts,unsigned int msec)17*25da2beaSAndroid Build Coastguard Worker static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec)
18*25da2beaSAndroid Build Coastguard Worker {
19*25da2beaSAndroid Build Coastguard Worker 	ts->tv_sec = msec / 1000;
20*25da2beaSAndroid Build Coastguard Worker 	ts->tv_nsec = (msec % 1000) * 1000000;
21*25da2beaSAndroid Build Coastguard Worker }
22*25da2beaSAndroid Build Coastguard Worker 
check_timeout_support(void)23*25da2beaSAndroid Build Coastguard Worker static int check_timeout_support(void)
24*25da2beaSAndroid Build Coastguard Worker {
25*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe;
26*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;
27*25da2beaSAndroid Build Coastguard Worker 	struct __kernel_timespec ts;
28*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_params p;
29*25da2beaSAndroid Build Coastguard Worker 	struct io_uring ring;
30*25da2beaSAndroid Build Coastguard Worker 	int ret;
31*25da2beaSAndroid Build Coastguard Worker 
32*25da2beaSAndroid Build Coastguard Worker 	memset(&p, 0, sizeof(p));
33*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_queue_init_params(1, &ring, &p);
34*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
35*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "ring setup failed: %d\n", ret);
36*25da2beaSAndroid Build Coastguard Worker 		return 1;
37*25da2beaSAndroid Build Coastguard Worker 	}
38*25da2beaSAndroid Build Coastguard Worker 
39*25da2beaSAndroid Build Coastguard Worker 	/* not really a match, but same kernel added batched completions */
40*25da2beaSAndroid Build Coastguard Worker 	if (p.features & IORING_FEAT_POLL_32BITS) {
41*25da2beaSAndroid Build Coastguard Worker 		fprintf(stdout, "Skipping\n");
42*25da2beaSAndroid Build Coastguard Worker 		not_supported = 1;
43*25da2beaSAndroid Build Coastguard Worker 		return 0;
44*25da2beaSAndroid Build Coastguard Worker 	}
45*25da2beaSAndroid Build Coastguard Worker 
46*25da2beaSAndroid Build Coastguard Worker 	sqe = io_uring_get_sqe(&ring);
47*25da2beaSAndroid Build Coastguard Worker 	msec_to_ts(&ts, TIMEOUT_MSEC);
48*25da2beaSAndroid Build Coastguard Worker 	io_uring_prep_timeout(sqe, &ts, 1, 0);
49*25da2beaSAndroid Build Coastguard Worker 
50*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_submit(&ring);
51*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
52*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "sqe submit failed: %d\n", ret);
53*25da2beaSAndroid Build Coastguard Worker 		goto err;
54*25da2beaSAndroid Build Coastguard Worker 	}
55*25da2beaSAndroid Build Coastguard Worker 
56*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_wait_cqe(&ring, &cqe);
57*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
58*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "wait completion %d\n", ret);
59*25da2beaSAndroid Build Coastguard Worker 		goto err;
60*25da2beaSAndroid Build Coastguard Worker 	}
61*25da2beaSAndroid Build Coastguard Worker 
62*25da2beaSAndroid Build Coastguard Worker 	if (cqe->res == -EINVAL) {
63*25da2beaSAndroid Build Coastguard Worker 		not_supported = 1;
64*25da2beaSAndroid Build Coastguard Worker 		fprintf(stdout, "Timeout not supported, ignored\n");
65*25da2beaSAndroid Build Coastguard Worker 		return 0;
66*25da2beaSAndroid Build Coastguard Worker 	}
67*25da2beaSAndroid Build Coastguard Worker 
68*25da2beaSAndroid Build Coastguard Worker 	io_uring_cqe_seen(&ring, cqe);
69*25da2beaSAndroid Build Coastguard Worker 	io_uring_queue_exit(&ring);
70*25da2beaSAndroid Build Coastguard Worker 	return 0;
71*25da2beaSAndroid Build Coastguard Worker err:
72*25da2beaSAndroid Build Coastguard Worker 	io_uring_queue_exit(&ring);
73*25da2beaSAndroid Build Coastguard Worker 	return 1;
74*25da2beaSAndroid Build Coastguard Worker }
75*25da2beaSAndroid Build Coastguard Worker 
76*25da2beaSAndroid Build Coastguard Worker /*
77*25da2beaSAndroid Build Coastguard Worker  * We first setup 4 timeout requests, which require a count value of 1, 1, 2,
78*25da2beaSAndroid Build Coastguard Worker  * UINT_MAX, so the sequence is 1, 2, 4, 2. Before really timeout, this 4
79*25da2beaSAndroid Build Coastguard Worker  * requests will not lead the change of cq_cached_tail, so as sq_dropped.
80*25da2beaSAndroid Build Coastguard Worker  *
81*25da2beaSAndroid Build Coastguard Worker  * And before this patch. The order of this four requests will be req1->req2->
82*25da2beaSAndroid Build Coastguard Worker  * req4->req3. Actually, it should be req1->req2->req3->req4.
83*25da2beaSAndroid Build Coastguard Worker  *
84*25da2beaSAndroid Build Coastguard Worker  * Then, if there is 2 nop req. All timeout requests expect req4 will completed
85*25da2beaSAndroid Build Coastguard Worker  * successful after the patch. And req1/req2 will completed successful with
86*25da2beaSAndroid Build Coastguard Worker  * req3/req4 return -ETIME without this patch!
87*25da2beaSAndroid Build Coastguard Worker  */
test_timeout_overflow(void)88*25da2beaSAndroid Build Coastguard Worker static int test_timeout_overflow(void)
89*25da2beaSAndroid Build Coastguard Worker {
90*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe;
91*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;
92*25da2beaSAndroid Build Coastguard Worker 	struct __kernel_timespec ts;
93*25da2beaSAndroid Build Coastguard Worker 	struct io_uring ring;
94*25da2beaSAndroid Build Coastguard Worker 	int i, ret;
95*25da2beaSAndroid Build Coastguard Worker 
96*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_queue_init(16, &ring, 0);
97*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
98*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "ring setup failed: %d\n", ret);
99*25da2beaSAndroid Build Coastguard Worker 		return 1;
100*25da2beaSAndroid Build Coastguard Worker 	}
101*25da2beaSAndroid Build Coastguard Worker 
102*25da2beaSAndroid Build Coastguard Worker 	msec_to_ts(&ts, TIMEOUT_MSEC);
103*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < 4; i++) {
104*25da2beaSAndroid Build Coastguard Worker 		unsigned num = 0;
105*25da2beaSAndroid Build Coastguard Worker 		sqe = io_uring_get_sqe(&ring);
106*25da2beaSAndroid Build Coastguard Worker 		switch (i) {
107*25da2beaSAndroid Build Coastguard Worker 		case 0:
108*25da2beaSAndroid Build Coastguard Worker 		case 1:
109*25da2beaSAndroid Build Coastguard Worker 			num = 1;
110*25da2beaSAndroid Build Coastguard Worker 			break;
111*25da2beaSAndroid Build Coastguard Worker 		case 2:
112*25da2beaSAndroid Build Coastguard Worker 			num = 2;
113*25da2beaSAndroid Build Coastguard Worker 			break;
114*25da2beaSAndroid Build Coastguard Worker 		case 3:
115*25da2beaSAndroid Build Coastguard Worker 			num = UINT_MAX;
116*25da2beaSAndroid Build Coastguard Worker 			break;
117*25da2beaSAndroid Build Coastguard Worker 		}
118*25da2beaSAndroid Build Coastguard Worker 		io_uring_prep_timeout(sqe, &ts, num, 0);
119*25da2beaSAndroid Build Coastguard Worker 	}
120*25da2beaSAndroid Build Coastguard Worker 
121*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < 2; i++) {
122*25da2beaSAndroid Build Coastguard Worker 		sqe = io_uring_get_sqe(&ring);
123*25da2beaSAndroid Build Coastguard Worker 		io_uring_prep_nop(sqe);
124*25da2beaSAndroid Build Coastguard Worker 		io_uring_sqe_set_data(sqe, (void *) 1);
125*25da2beaSAndroid Build Coastguard Worker 	}
126*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_submit(&ring);
127*25da2beaSAndroid Build Coastguard Worker 	if (ret < 0) {
128*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "sqe submit failed: %d\n", ret);
129*25da2beaSAndroid Build Coastguard Worker 		goto err;
130*25da2beaSAndroid Build Coastguard Worker 	}
131*25da2beaSAndroid Build Coastguard Worker 
132*25da2beaSAndroid Build Coastguard Worker 	i = 0;
133*25da2beaSAndroid Build Coastguard Worker 	while (i < 6) {
134*25da2beaSAndroid Build Coastguard Worker 		ret = io_uring_wait_cqe(&ring, &cqe);
135*25da2beaSAndroid Build Coastguard Worker 		if (ret < 0) {
136*25da2beaSAndroid Build Coastguard Worker 			fprintf(stderr, "wait completion %d\n", ret);
137*25da2beaSAndroid Build Coastguard Worker 			goto err;
138*25da2beaSAndroid Build Coastguard Worker 		}
139*25da2beaSAndroid Build Coastguard Worker 
140*25da2beaSAndroid Build Coastguard Worker 		/*
141*25da2beaSAndroid Build Coastguard Worker 		 * cqe1: first nop req
142*25da2beaSAndroid Build Coastguard Worker 		 * cqe2: first timeout req, because of cqe1
143*25da2beaSAndroid Build Coastguard Worker 		 * cqe3: second timeout req because of cqe1 + cqe2
144*25da2beaSAndroid Build Coastguard Worker 		 * cqe4: second nop req
145*25da2beaSAndroid Build Coastguard Worker 		 * cqe5~cqe6: the left three timeout req
146*25da2beaSAndroid Build Coastguard Worker 		 */
147*25da2beaSAndroid Build Coastguard Worker 		switch (i) {
148*25da2beaSAndroid Build Coastguard Worker 		case 0:
149*25da2beaSAndroid Build Coastguard Worker 		case 3:
150*25da2beaSAndroid Build Coastguard Worker 			if (io_uring_cqe_get_data(cqe) != (void *) 1) {
151*25da2beaSAndroid Build Coastguard Worker 				fprintf(stderr, "nop not seen as 1 or 2\n");
152*25da2beaSAndroid Build Coastguard Worker 				goto err;
153*25da2beaSAndroid Build Coastguard Worker 			}
154*25da2beaSAndroid Build Coastguard Worker 			break;
155*25da2beaSAndroid Build Coastguard Worker 		case 1:
156*25da2beaSAndroid Build Coastguard Worker 		case 2:
157*25da2beaSAndroid Build Coastguard Worker 		case 4:
158*25da2beaSAndroid Build Coastguard Worker 			if (cqe->res == -ETIME) {
159*25da2beaSAndroid Build Coastguard Worker 				fprintf(stderr, "expected not return -ETIME "
160*25da2beaSAndroid Build Coastguard Worker 					"for the #%d timeout req\n", i - 1);
161*25da2beaSAndroid Build Coastguard Worker 				goto err;
162*25da2beaSAndroid Build Coastguard Worker 			}
163*25da2beaSAndroid Build Coastguard Worker 			break;
164*25da2beaSAndroid Build Coastguard Worker 		case 5:
165*25da2beaSAndroid Build Coastguard Worker 			if (cqe->res != -ETIME) {
166*25da2beaSAndroid Build Coastguard Worker 				fprintf(stderr, "expected return -ETIME for "
167*25da2beaSAndroid Build Coastguard Worker 					"the #%d timeout req\n", i - 1);
168*25da2beaSAndroid Build Coastguard Worker 				goto err;
169*25da2beaSAndroid Build Coastguard Worker 			}
170*25da2beaSAndroid Build Coastguard Worker 			break;
171*25da2beaSAndroid Build Coastguard Worker 		}
172*25da2beaSAndroid Build Coastguard Worker 		io_uring_cqe_seen(&ring, cqe);
173*25da2beaSAndroid Build Coastguard Worker 		i++;
174*25da2beaSAndroid Build Coastguard Worker 	}
175*25da2beaSAndroid Build Coastguard Worker 
176*25da2beaSAndroid Build Coastguard Worker 	return 0;
177*25da2beaSAndroid Build Coastguard Worker err:
178*25da2beaSAndroid Build Coastguard Worker 	return 1;
179*25da2beaSAndroid Build Coastguard Worker }
180*25da2beaSAndroid Build Coastguard Worker 
main(int argc,char * argv[])181*25da2beaSAndroid Build Coastguard Worker int main(int argc, char *argv[])
182*25da2beaSAndroid Build Coastguard Worker {
183*25da2beaSAndroid Build Coastguard Worker 	int ret;
184*25da2beaSAndroid Build Coastguard Worker 
185*25da2beaSAndroid Build Coastguard Worker 	if (argc > 1)
186*25da2beaSAndroid Build Coastguard Worker 		return 0;
187*25da2beaSAndroid Build Coastguard Worker 
188*25da2beaSAndroid Build Coastguard Worker 	ret = check_timeout_support();
189*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
190*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "check_timeout_support failed: %d\n", ret);
191*25da2beaSAndroid Build Coastguard Worker 		return 1;
192*25da2beaSAndroid Build Coastguard Worker 	}
193*25da2beaSAndroid Build Coastguard Worker 
194*25da2beaSAndroid Build Coastguard Worker 	if (not_supported)
195*25da2beaSAndroid Build Coastguard Worker 		return 0;
196*25da2beaSAndroid Build Coastguard Worker 
197*25da2beaSAndroid Build Coastguard Worker 	ret = test_timeout_overflow();
198*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
199*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "test_timeout_overflow failed\n");
200*25da2beaSAndroid Build Coastguard Worker 		return 1;
201*25da2beaSAndroid Build Coastguard Worker 	}
202*25da2beaSAndroid Build Coastguard Worker 
203*25da2beaSAndroid Build Coastguard Worker 	return 0;
204*25da2beaSAndroid Build Coastguard Worker }
205