• 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 
try_close(struct io_uring * ring,int fd,int slot)38 static inline int try_close(struct io_uring *ring, int fd, int slot)
39 {
40 	struct io_uring_sqe *sqe;
41 
42 	sqe = io_uring_get_sqe(ring);
43 	io_uring_prep_close(sqe, fd);
44 	__io_uring_set_target_fixed_file(sqe, slot);
45 	return submit_wait(ring);
46 }
47 
test_close_fixed(void)48 static int test_close_fixed(void)
49 {
50 	struct io_uring ring;
51 	struct io_uring_sqe *sqe;
52 	int ret, fds[2];
53 	char buf[1];
54 
55 	ret = io_uring_queue_init(8, &ring, 0);
56 	if (ret) {
57 		fprintf(stderr, "ring setup failed\n");
58 		return -1;
59 	}
60 	if (pipe(fds)) {
61 		perror("pipe");
62 		return -1;
63 	}
64 
65 	ret = try_close(&ring, 0, 0);
66 	if (ret == -EINVAL) {
67 		fprintf(stderr, "close for fixed files is not supported\n");
68 		return 0;
69 	} else if (ret != -ENXIO) {
70 		fprintf(stderr, "no table failed %i\n", ret);
71 		return -1;
72 	}
73 
74 	ret = try_close(&ring, 1, 0);
75 	if (ret != -EINVAL) {
76 		fprintf(stderr, "set fd failed %i\n", ret);
77 		return -1;
78 	}
79 
80 	ret = io_uring_register_files(&ring, fds, 2);
81 	if (ret) {
82 		fprintf(stderr, "file_register: %d\n", ret);
83 		return ret;
84 	}
85 
86 	ret = try_close(&ring, 0, 2);
87 	if (ret != -EINVAL) {
88 		fprintf(stderr, "out of table failed %i\n", ret);
89 		return -1;
90 	}
91 
92 	ret = try_close(&ring, 0, 0);
93 	if (ret != 0) {
94 		fprintf(stderr, "close failed %i\n", ret);
95 		return -1;
96 	}
97 
98 	sqe = io_uring_get_sqe(&ring);
99 	io_uring_prep_read(sqe, 0, buf, sizeof(buf), 0);
100 	sqe->flags |= IOSQE_FIXED_FILE;
101 	ret = submit_wait(&ring);
102 	if (ret != -EBADF) {
103 		fprintf(stderr, "read failed %i\n", ret);
104 		return -1;
105 	}
106 
107 	ret = try_close(&ring, 0, 1);
108 	if (ret != 0) {
109 		fprintf(stderr, "close 2 failed %i\n", ret);
110 		return -1;
111 	}
112 
113 	ret = try_close(&ring, 0, 0);
114 	if (ret != -EBADF) {
115 		fprintf(stderr, "empty slot failed %i\n", ret);
116 		return -1;
117 	}
118 
119 	close(fds[0]);
120 	close(fds[1]);
121 	io_uring_queue_exit(&ring);
122 	return 0;
123 }
124 
test_close(struct io_uring * ring,int fd,int is_ring_fd)125 static int test_close(struct io_uring *ring, int fd, int is_ring_fd)
126 {
127 	struct io_uring_cqe *cqe;
128 	struct io_uring_sqe *sqe;
129 	int ret;
130 
131 	sqe = io_uring_get_sqe(ring);
132 	if (!sqe) {
133 		fprintf(stderr, "get sqe failed\n");
134 		goto err;
135 	}
136 	io_uring_prep_close(sqe, fd);
137 
138 	ret = io_uring_submit(ring);
139 	if (ret <= 0) {
140 		fprintf(stderr, "sqe submit failed: %d\n", ret);
141 		goto err;
142 	}
143 
144 	ret = io_uring_wait_cqe(ring, &cqe);
145 	if (ret < 0) {
146 		if (!(is_ring_fd && ret == -EBADF)) {
147 			fprintf(stderr, "wait completion %d\n", ret);
148 			goto err;
149 		}
150 		return ret;
151 	}
152 	ret = cqe->res;
153 	io_uring_cqe_seen(ring, cqe);
154 	return ret;
155 err:
156 	return -1;
157 }
158 
test_openat(struct io_uring * ring,const char * path,int dfd)159 static int test_openat(struct io_uring *ring, const char *path, int dfd)
160 {
161 	struct io_uring_cqe *cqe;
162 	struct io_uring_sqe *sqe;
163 	int ret;
164 
165 	sqe = io_uring_get_sqe(ring);
166 	if (!sqe) {
167 		fprintf(stderr, "get sqe failed\n");
168 		goto err;
169 	}
170 	io_uring_prep_openat(sqe, dfd, path, O_RDONLY, 0);
171 
172 	ret = io_uring_submit(ring);
173 	if (ret <= 0) {
174 		fprintf(stderr, "sqe submit failed: %d\n", ret);
175 		goto err;
176 	}
177 
178 	ret = io_uring_wait_cqe(ring, &cqe);
179 	if (ret < 0) {
180 		fprintf(stderr, "wait completion %d\n", ret);
181 		goto err;
182 	}
183 	ret = cqe->res;
184 	io_uring_cqe_seen(ring, cqe);
185 	return ret;
186 err:
187 	return -1;
188 }
189 
main(int argc,char * argv[])190 int main(int argc, char *argv[])
191 {
192 	struct io_uring ring;
193 	const char *path, *path_rel;
194 	int ret, do_unlink;
195 
196 	ret = io_uring_queue_init(8, &ring, 0);
197 	if (ret) {
198 		fprintf(stderr, "ring setup failed\n");
199 		return 1;
200 	}
201 
202 	if (argc > 1) {
203 		path = "/tmp/.open.close";
204 		path_rel = argv[1];
205 		do_unlink = 0;
206 	} else {
207 		path = "/tmp/.open.close";
208 		path_rel = ".open.close";
209 		do_unlink = 1;
210 	}
211 
212 	t_create_file(path, 4096);
213 
214 	if (do_unlink)
215 		t_create_file(path_rel, 4096);
216 
217 	ret = test_openat(&ring, path, -1);
218 	if (ret < 0) {
219 		if (ret == -EINVAL) {
220 			fprintf(stdout, "Open not supported, skipping\n");
221 			goto done;
222 		}
223 		fprintf(stderr, "test_openat absolute failed: %d\n", ret);
224 		goto err;
225 	}
226 
227 	ret = test_openat(&ring, path_rel, AT_FDCWD);
228 	if (ret < 0) {
229 		fprintf(stderr, "test_openat relative failed: %d\n", ret);
230 		goto err;
231 	}
232 
233 	ret = test_close(&ring, ret, 0);
234 	if (ret) {
235 		fprintf(stderr, "test_close normal failed\n");
236 		goto err;
237 	}
238 
239 	ret = test_close(&ring, ring.ring_fd, 1);
240 	if (ret != -EBADF) {
241 		fprintf(stderr, "test_close ring_fd failed\n");
242 		goto err;
243 	}
244 
245 	ret = test_close_fixed();
246 	if (ret) {
247 		fprintf(stderr, "test_close_fixed failed\n");
248 		goto err;
249 	}
250 
251 done:
252 	unlink(path);
253 	if (do_unlink)
254 		unlink(path_rel);
255 	return 0;
256 err:
257 	unlink(path);
258 	if (do_unlink)
259 		unlink(path_rel);
260 	return 1;
261 }
262