xref: /aosp_15_r20/external/liburing/test/submit-link-fail.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker /*
3*25da2beaSAndroid Build Coastguard Worker  * Description: tests linked requests failing during submission
4*25da2beaSAndroid Build Coastguard Worker  */
5*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
6*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
7*25da2beaSAndroid Build Coastguard Worker #include <unistd.h>
8*25da2beaSAndroid Build Coastguard Worker #include <stdlib.h>
9*25da2beaSAndroid Build Coastguard Worker #include <string.h>
10*25da2beaSAndroid Build Coastguard Worker #include <fcntl.h>
11*25da2beaSAndroid Build Coastguard Worker #include <assert.h>
12*25da2beaSAndroid Build Coastguard Worker 
13*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
14*25da2beaSAndroid Build Coastguard Worker 
15*25da2beaSAndroid Build Coastguard Worker #define DRAIN_USER_DATA 42
16*25da2beaSAndroid Build Coastguard Worker 
test_underprep_fail(bool hardlink,bool drain,bool link_last,int link_size,int fail_idx)17*25da2beaSAndroid Build Coastguard Worker static int test_underprep_fail(bool hardlink, bool drain, bool link_last,
18*25da2beaSAndroid Build Coastguard Worker 			       int link_size, int fail_idx)
19*25da2beaSAndroid Build Coastguard Worker {
20*25da2beaSAndroid Build Coastguard Worker 	const int invalid_fd = 42;
21*25da2beaSAndroid Build Coastguard Worker 	int link_flags = IOSQE_IO_LINK;
22*25da2beaSAndroid Build Coastguard Worker 	int total_submit = link_size;
23*25da2beaSAndroid Build Coastguard Worker 	struct io_uring ring;
24*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_sqe *sqe;
25*25da2beaSAndroid Build Coastguard Worker 	struct io_uring_cqe *cqe;
26*25da2beaSAndroid Build Coastguard Worker 	char buffer[1];
27*25da2beaSAndroid Build Coastguard Worker 	int i, ret, fds[2];
28*25da2beaSAndroid Build Coastguard Worker 
29*25da2beaSAndroid Build Coastguard Worker 	if (drain)
30*25da2beaSAndroid Build Coastguard Worker 		link_flags |= IOSQE_IO_DRAIN;
31*25da2beaSAndroid Build Coastguard Worker 	if (hardlink)
32*25da2beaSAndroid Build Coastguard Worker 		link_flags |= IOSQE_IO_HARDLINK;
33*25da2beaSAndroid Build Coastguard Worker 
34*25da2beaSAndroid Build Coastguard Worker 	assert(fail_idx < link_size);
35*25da2beaSAndroid Build Coastguard Worker 	assert(link_size < 40);
36*25da2beaSAndroid Build Coastguard Worker 
37*25da2beaSAndroid Build Coastguard Worker 	/* create a new ring as it leaves it dirty */
38*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_queue_init(8, &ring, 0);
39*25da2beaSAndroid Build Coastguard Worker 	if (ret) {
40*25da2beaSAndroid Build Coastguard Worker 		printf("ring setup failed\n");
41*25da2beaSAndroid Build Coastguard Worker 		return -1;
42*25da2beaSAndroid Build Coastguard Worker 	}
43*25da2beaSAndroid Build Coastguard Worker 	if (pipe(fds)) {
44*25da2beaSAndroid Build Coastguard Worker 		perror("pipe");
45*25da2beaSAndroid Build Coastguard Worker 		return -1;
46*25da2beaSAndroid Build Coastguard Worker 	}
47*25da2beaSAndroid Build Coastguard Worker 
48*25da2beaSAndroid Build Coastguard Worker 	if (drain) {
49*25da2beaSAndroid Build Coastguard Worker 		/* clog drain, so following reqs sent to draining */
50*25da2beaSAndroid Build Coastguard Worker 		sqe = io_uring_get_sqe(&ring);
51*25da2beaSAndroid Build Coastguard Worker 		io_uring_prep_read(sqe, fds[0], buffer, sizeof(buffer), 0);
52*25da2beaSAndroid Build Coastguard Worker 		sqe->user_data = DRAIN_USER_DATA;
53*25da2beaSAndroid Build Coastguard Worker 		sqe->flags |= IOSQE_IO_DRAIN;
54*25da2beaSAndroid Build Coastguard Worker 		total_submit++;
55*25da2beaSAndroid Build Coastguard Worker 	}
56*25da2beaSAndroid Build Coastguard Worker 
57*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < link_size; i++) {
58*25da2beaSAndroid Build Coastguard Worker 		sqe = io_uring_get_sqe(&ring);
59*25da2beaSAndroid Build Coastguard Worker 		if (i == fail_idx) {
60*25da2beaSAndroid Build Coastguard Worker 			io_uring_prep_read(sqe, invalid_fd, buffer, 1, 0);
61*25da2beaSAndroid Build Coastguard Worker 			sqe->ioprio = (short) -1;
62*25da2beaSAndroid Build Coastguard Worker 		} else {
63*25da2beaSAndroid Build Coastguard Worker 			io_uring_prep_nop(sqe);
64*25da2beaSAndroid Build Coastguard Worker 		}
65*25da2beaSAndroid Build Coastguard Worker 
66*25da2beaSAndroid Build Coastguard Worker 		if (i != link_size - 1 || !link_last)
67*25da2beaSAndroid Build Coastguard Worker 			sqe->flags |= link_flags;
68*25da2beaSAndroid Build Coastguard Worker 		sqe->user_data = i;
69*25da2beaSAndroid Build Coastguard Worker 	}
70*25da2beaSAndroid Build Coastguard Worker 
71*25da2beaSAndroid Build Coastguard Worker 	ret = io_uring_submit(&ring);
72*25da2beaSAndroid Build Coastguard Worker 	if (ret != total_submit) {
73*25da2beaSAndroid Build Coastguard Worker 		/* Old behaviour, failed early and under-submitted */
74*25da2beaSAndroid Build Coastguard Worker 		if (ret == fail_idx + 1 + drain)
75*25da2beaSAndroid Build Coastguard Worker 			goto out;
76*25da2beaSAndroid Build Coastguard Worker 		fprintf(stderr, "submit failed: %d\n", ret);
77*25da2beaSAndroid Build Coastguard Worker 		return -1;
78*25da2beaSAndroid Build Coastguard Worker 	}
79*25da2beaSAndroid Build Coastguard Worker 
80*25da2beaSAndroid Build Coastguard Worker 	if (drain) {
81*25da2beaSAndroid Build Coastguard Worker 		/* unclog drain */
82*25da2beaSAndroid Build Coastguard Worker 		ret = write(fds[1], buffer, sizeof(buffer));
83*25da2beaSAndroid Build Coastguard Worker 		if (ret < 0) {
84*25da2beaSAndroid Build Coastguard Worker 			perror("write");
85*25da2beaSAndroid Build Coastguard Worker 			return 1;
86*25da2beaSAndroid Build Coastguard Worker 		}
87*25da2beaSAndroid Build Coastguard Worker 	}
88*25da2beaSAndroid Build Coastguard Worker 
89*25da2beaSAndroid Build Coastguard Worker 	for (i = 0; i < total_submit; i++) {
90*25da2beaSAndroid Build Coastguard Worker 		ret = io_uring_wait_cqe(&ring, &cqe);
91*25da2beaSAndroid Build Coastguard Worker 		if (ret) {
92*25da2beaSAndroid Build Coastguard Worker 			fprintf(stderr, "wait_cqe=%d\n", ret);
93*25da2beaSAndroid Build Coastguard Worker 			return 1;
94*25da2beaSAndroid Build Coastguard Worker 		}
95*25da2beaSAndroid Build Coastguard Worker 
96*25da2beaSAndroid Build Coastguard Worker 		ret = cqe->res;
97*25da2beaSAndroid Build Coastguard Worker 		if (cqe->user_data == DRAIN_USER_DATA) {
98*25da2beaSAndroid Build Coastguard Worker 			if (ret != 1) {
99*25da2beaSAndroid Build Coastguard Worker 				fprintf(stderr, "drain failed %d\n", ret);
100*25da2beaSAndroid Build Coastguard Worker 				return 1;
101*25da2beaSAndroid Build Coastguard Worker 			}
102*25da2beaSAndroid Build Coastguard Worker 		} else if (cqe->user_data == fail_idx) {
103*25da2beaSAndroid Build Coastguard Worker 			if (ret == 0 || ret == -ECANCELED) {
104*25da2beaSAndroid Build Coastguard Worker 				fprintf(stderr, "half-prep req unexpected return %d\n", ret);
105*25da2beaSAndroid Build Coastguard Worker 				return 1;
106*25da2beaSAndroid Build Coastguard Worker 			}
107*25da2beaSAndroid Build Coastguard Worker 		} else {
108*25da2beaSAndroid Build Coastguard Worker 			if (ret != -ECANCELED) {
109*25da2beaSAndroid Build Coastguard Worker 				fprintf(stderr, "cancel failed %d, ud %d\n", ret, (int)cqe->user_data);
110*25da2beaSAndroid Build Coastguard Worker 				return 1;
111*25da2beaSAndroid Build Coastguard Worker 			}
112*25da2beaSAndroid Build Coastguard Worker 		}
113*25da2beaSAndroid Build Coastguard Worker 		io_uring_cqe_seen(&ring, cqe);
114*25da2beaSAndroid Build Coastguard Worker 	}
115*25da2beaSAndroid Build Coastguard Worker out:
116*25da2beaSAndroid Build Coastguard Worker 	close(fds[0]);
117*25da2beaSAndroid Build Coastguard Worker 	close(fds[1]);
118*25da2beaSAndroid Build Coastguard Worker 	io_uring_queue_exit(&ring);
119*25da2beaSAndroid Build Coastguard Worker 	return 0;
120*25da2beaSAndroid Build Coastguard Worker }
121*25da2beaSAndroid Build Coastguard Worker 
main(int argc,char * argv[])122*25da2beaSAndroid Build Coastguard Worker int main(int argc, char *argv[])
123*25da2beaSAndroid Build Coastguard Worker {
124*25da2beaSAndroid Build Coastguard Worker 	int ret, link_size, fail_idx, i;
125*25da2beaSAndroid Build Coastguard Worker 
126*25da2beaSAndroid Build Coastguard Worker 	if (argc > 1)
127*25da2beaSAndroid Build Coastguard Worker 		return 0;
128*25da2beaSAndroid Build Coastguard Worker 
129*25da2beaSAndroid Build Coastguard Worker 	/*
130*25da2beaSAndroid Build Coastguard Worker 	 * hardlink, size=3, fail_idx=1, drain=false -- kernel fault
131*25da2beaSAndroid Build Coastguard Worker 	 * link, size=3, fail_idx=0, drain=true -- kernel fault
132*25da2beaSAndroid Build Coastguard Worker 	 * link, size=3, fail_idx=1, drain=true -- invalid cqe->res
133*25da2beaSAndroid Build Coastguard Worker 	 */
134*25da2beaSAndroid Build Coastguard Worker 	for (link_size = 0; link_size < 3; link_size++) {
135*25da2beaSAndroid Build Coastguard Worker 		for (fail_idx = 0; fail_idx < link_size; fail_idx++) {
136*25da2beaSAndroid Build Coastguard Worker 			for (i = 0; i < 8; i++) {
137*25da2beaSAndroid Build Coastguard Worker 				bool hardlink = (i & 1) != 0;
138*25da2beaSAndroid Build Coastguard Worker 				bool drain = (i & 2) != 0;
139*25da2beaSAndroid Build Coastguard Worker 				bool link_last = (i & 4) != 0;
140*25da2beaSAndroid Build Coastguard Worker 
141*25da2beaSAndroid Build Coastguard Worker 				ret = test_underprep_fail(hardlink, drain, link_last,
142*25da2beaSAndroid Build Coastguard Worker 							  link_size, fail_idx);
143*25da2beaSAndroid Build Coastguard Worker 				if (!ret)
144*25da2beaSAndroid Build Coastguard Worker 					continue;
145*25da2beaSAndroid Build Coastguard Worker 
146*25da2beaSAndroid Build Coastguard Worker 				fprintf(stderr, "failed %d, hard %d, drain %d,"
147*25da2beaSAndroid Build Coastguard Worker 						"link_last %d, size %d, idx %d\n",
148*25da2beaSAndroid Build Coastguard Worker 						ret, hardlink, drain, link_last,
149*25da2beaSAndroid Build Coastguard Worker 						link_size, fail_idx);
150*25da2beaSAndroid Build Coastguard Worker 				return 1;
151*25da2beaSAndroid Build Coastguard Worker 			}
152*25da2beaSAndroid Build Coastguard Worker 		}
153*25da2beaSAndroid Build Coastguard Worker 	}
154*25da2beaSAndroid Build Coastguard Worker 
155*25da2beaSAndroid Build Coastguard Worker 	return 0;
156*25da2beaSAndroid Build Coastguard Worker }
157