• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: link <open file><read from file><close file>
4  *
5  */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 
13 #include "liburing.h"
14 #include "helpers.h"
15 
16 #define MAX_FILES	8
17 #define FNAME		".link.direct"
18 
test(struct io_uring * ring,int skip_success,int drain,int async)19 static int test(struct io_uring *ring, int skip_success, int drain, int async)
20 {
21 	struct io_uring_cqe *cqe;
22 	struct io_uring_sqe *sqe;
23 	char buf[4096];
24 	int ret, i;
25 
26 	/* drain and cqe skip are mutually exclusive */
27 	if (skip_success && drain)
28 		return 1;
29 
30 	sqe = io_uring_get_sqe(ring);
31 	io_uring_prep_openat_direct(sqe, AT_FDCWD, FNAME, O_RDONLY, 0, 0);
32 	if (!drain)
33 		sqe->flags |= IOSQE_IO_LINK;
34 	if (skip_success)
35 		sqe->flags |= IOSQE_CQE_SKIP_SUCCESS;
36 	if (async)
37 		sqe->flags |= IOSQE_ASYNC;
38 	sqe->user_data = 1;
39 
40 	sqe = io_uring_get_sqe(ring);
41 	io_uring_prep_read(sqe, 0, buf, sizeof(buf), 0);
42 	sqe->flags |= IOSQE_FIXED_FILE;
43 	if (drain)
44 		sqe->flags |= IOSQE_IO_DRAIN;
45 	else
46 		sqe->flags |= IOSQE_IO_LINK;
47 	if (async)
48 		sqe->flags |= IOSQE_ASYNC;
49 	sqe->user_data = 2;
50 
51 	sqe = io_uring_get_sqe(ring);
52 	io_uring_prep_close_direct(sqe, 0);
53 	sqe->user_data = 3;
54 	if (skip_success)
55 		sqe->flags |= IOSQE_CQE_SKIP_SUCCESS;
56 	if (drain)
57 		sqe->flags |= IOSQE_IO_DRAIN;
58 	if (async)
59 		sqe->flags |= IOSQE_ASYNC;
60 
61 	ret = io_uring_submit(ring);
62 	if (ret != 3) {
63 		fprintf(stderr, "sqe submit failed: %d\n", ret);
64 		goto err;
65 	}
66 
67 	if (skip_success) {
68 		ret = io_uring_wait_cqe(ring, &cqe);
69 		if (ret < 0) {
70 			fprintf(stderr, "wait completion %d\n", ret);
71 			goto err;
72 		}
73 		if (cqe->user_data != 2) {
74 			fprintf(stderr, "Unexpected cqe %lu/%d\n",
75 					(unsigned long) cqe->user_data,
76 					cqe->res);
77 			goto err;
78 		}
79 		if (cqe->res != sizeof(buf)) {
80 			fprintf(stderr, "bad read %d\n", cqe->res);
81 			goto err;
82 		}
83 		io_uring_cqe_seen(ring, cqe);
84 		return 0;
85 	}
86 
87 	for (i = 0; i < 3; i++) {
88 		ret = io_uring_wait_cqe(ring, &cqe);
89 		if (ret < 0) {
90 			fprintf(stderr, "wait completion %d\n", ret);
91 			goto err;
92 		}
93 		switch (cqe->user_data) {
94 		case 1:
95 			if (cqe->res) {
96 				fprintf(stderr, "bad open %d\n", cqe->res);
97 				goto err;
98 			}
99 			break;
100 		case 2:
101 			if (cqe->res != sizeof(buf)) {
102 				fprintf(stderr, "bad read %d\n", cqe->res);
103 				goto err;
104 			}
105 			break;
106 		case 3:
107 			if (cqe->res) {
108 				fprintf(stderr, "bad close %d\n", cqe->res);
109 				goto err;
110 			}
111 			break;
112 		}
113 		io_uring_cqe_seen(ring, cqe);
114 	}
115 
116 	return 0;
117 err:
118 	return 1;
119 }
120 
main(int argc,char * argv[])121 int main(int argc, char *argv[])
122 {
123 	struct io_uring ring;
124 	struct io_uring_params p = { };
125 	int ret, files[MAX_FILES];
126 
127 	if (argc > 1)
128 		return 0;
129 
130 	ret = io_uring_queue_init_params(8, &ring, &p);
131 	if (ret) {
132 		fprintf(stderr, "ring setup failed: %d\n", ret);
133 		return 1;
134 	}
135 	if (!(p.features & IORING_FEAT_CQE_SKIP))
136 		return 0;
137 
138 	memset(files, -1, sizeof(files));
139 	ret = io_uring_register_files(&ring, files, ARRAY_SIZE(files));
140 	if (ret) {
141 		fprintf(stderr, "Failed registering files\n");
142 		return 1;
143 	}
144 
145 	t_create_file(FNAME, 4096);
146 
147 	ret = test(&ring, 0, 0, 0);
148 	if (ret) {
149 		fprintf(stderr, "test 0 0 0 failed\n");
150 		goto err;
151 	}
152 
153 	ret = test(&ring, 0, 1, 0);
154 	if (ret) {
155 		fprintf(stderr, "test 0 1 0 failed\n");
156 		goto err;
157 	}
158 
159 	ret = test(&ring, 0, 0, 1);
160 	if (ret) {
161 		fprintf(stderr, "test 0 0 1 failed\n");
162 		goto err;
163 	}
164 
165 	ret = test(&ring, 0, 1, 1);
166 	if (ret) {
167 		fprintf(stderr, "test 0 1 1 failed\n");
168 		goto err;
169 	}
170 
171 	ret = test(&ring, 1, 0, 0);
172 	if (ret) {
173 		fprintf(stderr, "test 1 0 0 failed\n");
174 		goto err;
175 	}
176 
177 	ret = test(&ring, 1, 0, 1);
178 	if (ret) {
179 		fprintf(stderr, "test 1 0 1 failed\n");
180 		goto err;
181 	}
182 
183 	unlink(FNAME);
184 	return 0;
185 err:
186 	unlink(FNAME);
187 	return 1;
188 }
189