• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: run various openat(2) tests
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 #include <assert.h>
13 
14 #include "helpers.h"
15 #include "liburing.h"
16 
submit_wait(struct io_uring * ring)17 static int submit_wait(struct io_uring *ring)
18 {
19 	struct io_uring_cqe *cqe;
20 	int ret;
21 
22 	ret = io_uring_submit(ring);
23 	if (ret <= 0) {
24 		fprintf(stderr, "sqe submit failed: %d\n", ret);
25 		return 1;
26 	}
27 	ret = io_uring_wait_cqe(ring, &cqe);
28 	if (ret < 0) {
29 		fprintf(stderr, "wait completion %d\n", ret);
30 		return 1;
31 	}
32 
33 	ret = cqe->res;
34 	io_uring_cqe_seen(ring, cqe);
35 	return ret;
36 }
37 
test_close_flush(void)38 static int test_close_flush(void)
39 {
40 	struct io_uring ring;
41 	struct io_uring_sqe *sqe;
42 	char buf[128];
43 	int ret, fd;
44 
45 	sprintf(buf, "/sys/kernel/debug/tracing/per_cpu/cpu0/trace_pipe_raw");
46 	fd = open(buf, O_RDONLY);
47 	if (fd < 0)
48 		return 0;
49 
50 	ret = io_uring_queue_init(8, &ring, 0);
51 	if (ret) {
52 		fprintf(stderr, "ring setup failed\n");
53 		return -1;
54 	}
55 
56 	sqe = io_uring_get_sqe(&ring);
57 	io_uring_prep_close(sqe, fd);
58 	ret = submit_wait(&ring);
59 	if (ret) {
60 		fprintf(stderr, "closefailed %i\n", ret);
61 		return -1;
62 	}
63 
64 	io_uring_queue_exit(&ring);
65 	return 0;
66 }
67 
try_close(struct io_uring * ring,int fd,int slot)68 static inline int try_close(struct io_uring *ring, int fd, int slot)
69 {
70 	struct io_uring_sqe *sqe;
71 
72 	sqe = io_uring_get_sqe(ring);
73 	io_uring_prep_close(sqe, fd);
74 	__io_uring_set_target_fixed_file(sqe, slot);
75 	return submit_wait(ring);
76 }
77 
test_close_fixed(void)78 static int test_close_fixed(void)
79 {
80 	struct io_uring ring;
81 	struct io_uring_sqe *sqe;
82 	int ret, fds[2];
83 	char buf[1];
84 
85 	ret = io_uring_queue_init(8, &ring, 0);
86 	if (ret) {
87 		fprintf(stderr, "ring setup failed\n");
88 		return -1;
89 	}
90 	if (pipe(fds)) {
91 		perror("pipe");
92 		return -1;
93 	}
94 
95 	ret = try_close(&ring, 0, 0);
96 	if (ret == -EINVAL) {
97 		fprintf(stderr, "close for fixed files is not supported\n");
98 		return 0;
99 	} else if (ret != -ENXIO) {
100 		fprintf(stderr, "no table failed %i\n", ret);
101 		return -1;
102 	}
103 
104 	ret = try_close(&ring, 1, 0);
105 	if (ret != -EINVAL) {
106 		fprintf(stderr, "set fd failed %i\n", ret);
107 		return -1;
108 	}
109 
110 	ret = io_uring_register_files(&ring, fds, 2);
111 	if (ret) {
112 		fprintf(stderr, "file_register: %d\n", ret);
113 		return ret;
114 	}
115 
116 	ret = try_close(&ring, 0, 2);
117 	if (ret != -EINVAL) {
118 		fprintf(stderr, "out of table failed %i\n", ret);
119 		return -1;
120 	}
121 
122 	ret = try_close(&ring, 0, 0);
123 	if (ret != 0) {
124 		fprintf(stderr, "close failed %i\n", ret);
125 		return -1;
126 	}
127 
128 	sqe = io_uring_get_sqe(&ring);
129 	io_uring_prep_read(sqe, 0, buf, sizeof(buf), 0);
130 	sqe->flags |= IOSQE_FIXED_FILE;
131 	ret = submit_wait(&ring);
132 	if (ret != -EBADF) {
133 		fprintf(stderr, "read failed %i\n", ret);
134 		return -1;
135 	}
136 
137 	ret = try_close(&ring, 0, 1);
138 	if (ret != 0) {
139 		fprintf(stderr, "close 2 failed %i\n", ret);
140 		return -1;
141 	}
142 
143 	ret = try_close(&ring, 0, 0);
144 	if (ret != -EBADF) {
145 		fprintf(stderr, "empty slot failed %i\n", ret);
146 		return -1;
147 	}
148 
149 	close(fds[0]);
150 	close(fds[1]);
151 	io_uring_queue_exit(&ring);
152 	return 0;
153 }
154 
test_close(struct io_uring * ring,int fd,int is_ring_fd)155 static int test_close(struct io_uring *ring, int fd, int is_ring_fd)
156 {
157 	struct io_uring_cqe *cqe;
158 	struct io_uring_sqe *sqe;
159 	int ret;
160 
161 	sqe = io_uring_get_sqe(ring);
162 	if (!sqe) {
163 		fprintf(stderr, "get sqe failed\n");
164 		goto err;
165 	}
166 	io_uring_prep_close(sqe, fd);
167 
168 	ret = io_uring_submit(ring);
169 	if (ret <= 0) {
170 		fprintf(stderr, "sqe submit failed: %d\n", ret);
171 		goto err;
172 	}
173 
174 	ret = io_uring_wait_cqe(ring, &cqe);
175 	if (ret < 0) {
176 		if (!(is_ring_fd && ret == -EBADF)) {
177 			fprintf(stderr, "wait completion %d\n", ret);
178 			goto err;
179 		}
180 		return ret;
181 	}
182 	ret = cqe->res;
183 	io_uring_cqe_seen(ring, cqe);
184 	return ret;
185 err:
186 	return -1;
187 }
188 
test_openat(struct io_uring * ring,const char * path,int dfd)189 static int test_openat(struct io_uring *ring, const char *path, int dfd)
190 {
191 	struct io_uring_cqe *cqe;
192 	struct io_uring_sqe *sqe;
193 	int ret;
194 
195 	sqe = io_uring_get_sqe(ring);
196 	if (!sqe) {
197 		fprintf(stderr, "get sqe failed\n");
198 		goto err;
199 	}
200 	io_uring_prep_openat(sqe, dfd, path, O_RDONLY, 0);
201 
202 	ret = io_uring_submit(ring);
203 	if (ret <= 0) {
204 		fprintf(stderr, "sqe submit failed: %d\n", ret);
205 		goto err;
206 	}
207 
208 	ret = io_uring_wait_cqe(ring, &cqe);
209 	if (ret < 0) {
210 		fprintf(stderr, "wait completion %d\n", ret);
211 		goto err;
212 	}
213 	ret = cqe->res;
214 	io_uring_cqe_seen(ring, cqe);
215 	return ret;
216 err:
217 	return -1;
218 }
219 
main(int argc,char * argv[])220 int main(int argc, char *argv[])
221 {
222 	struct io_uring ring;
223 	const char *path, *path_rel;
224 	int ret, do_unlink;
225 
226 	ret = io_uring_queue_init(8, &ring, 0);
227 	if (ret) {
228 		fprintf(stderr, "ring setup failed\n");
229 		return 1;
230 	}
231 
232 	if (argc > 1) {
233 		path = "/tmp/.open.close";
234 		path_rel = argv[1];
235 		do_unlink = 0;
236 	} else {
237 		path = "/tmp/.open.close";
238 		path_rel = ".open.close";
239 		do_unlink = 1;
240 	}
241 
242 	t_create_file(path, 4096);
243 
244 	if (do_unlink)
245 		t_create_file(path_rel, 4096);
246 
247 	ret = test_openat(&ring, path, -1);
248 	if (ret < 0) {
249 		if (ret == -EINVAL) {
250 			fprintf(stdout, "Open not supported, skipping\n");
251 			goto done;
252 		}
253 		if (ret == -EPERM || ret == -EACCES)
254 			return T_EXIT_SKIP;
255 		fprintf(stderr, "test_openat absolute failed: %d\n", ret);
256 		goto err;
257 	}
258 
259 	ret = test_openat(&ring, path_rel, AT_FDCWD);
260 	if (ret < 0) {
261 		if (ret == -EPERM || ret == -EACCES)
262 			return T_EXIT_SKIP;
263 		fprintf(stderr, "test_openat relative failed: %d\n", ret);
264 		goto err;
265 	}
266 
267 	ret = test_close(&ring, ret, 0);
268 	if (ret) {
269 		fprintf(stderr, "test_close normal failed\n");
270 		goto err;
271 	}
272 
273 	ret = test_close(&ring, ring.ring_fd, 1);
274 	if (ret != -EBADF) {
275 		fprintf(stderr, "test_close ring_fd failed\n");
276 		goto err;
277 	}
278 
279 	ret = test_close_fixed();
280 	if (ret) {
281 		fprintf(stderr, "test_close_fixed failed\n");
282 		goto err;
283 	}
284 
285 	ret = test_close_flush();
286 	if (ret) {
287 		fprintf(stderr, "test_close_flush failed\n");
288 		goto err;
289 	}
290 
291 done:
292 	unlink(path);
293 	if (do_unlink)
294 		unlink(path_rel);
295 	return 0;
296 err:
297 	unlink(path);
298 	if (do_unlink)
299 		unlink(path_rel);
300 	return 1;
301 }
302