xref: /aosp_15_r20/external/liburing/test/lfs-openat.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1 /* SPDX-License-Identifier: MIT */
2 
3 #define _LARGEFILE_SOURCE
4 #define _FILE_OFFSET_BITS 64
5 
6 #include <string.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <errno.h>
13 #include <sys/resource.h>
14 #include <unistd.h>
15 
16 #include "liburing.h"
17 
18 #define DIE(...) do {\
19 		fprintf(stderr, __VA_ARGS__);\
20 		abort();\
21 	} while(0);
22 
23 static const int RSIZE = 2;
24 static const int OPEN_FLAGS = O_RDWR | O_CREAT;
25 static const mode_t OPEN_MODE = S_IRUSR | S_IWUSR;
26 
open_io_uring(struct io_uring * ring,int dfd,const char * fn)27 static int open_io_uring(struct io_uring *ring, int dfd, const char *fn)
28 {
29 	struct io_uring_sqe *sqe;
30 	struct io_uring_cqe *cqe;
31 	int ret, fd;
32 
33 	sqe = io_uring_get_sqe(ring);
34 	if (!sqe) {
35 		fprintf(stderr, "failed to get sqe\n");
36 		return 1;
37 	}
38 	io_uring_prep_openat(sqe, dfd, fn, OPEN_FLAGS, OPEN_MODE);
39 
40 	ret = io_uring_submit(ring);
41 	if (ret < 0) {
42 		fprintf(stderr, "failed to submit openat: %s\n", strerror(-ret));
43 		return 1;
44 	}
45 
46 	ret = io_uring_wait_cqe(ring, &cqe);
47 	fd = cqe->res;
48 	io_uring_cqe_seen(ring, cqe);
49 	if (ret < 0) {
50 		fprintf(stderr, "wait_cqe failed: %s\n", strerror(-ret));
51 		return 1;
52 	} else if (fd < 0) {
53 		fprintf(stderr, "io_uring openat failed: %s\n", strerror(-fd));
54 		return 1;
55 	}
56 
57 	close(fd);
58 	return 0;
59 }
60 
prepare_file(int dfd,const char * fn)61 static int prepare_file(int dfd, const char* fn)
62 {
63 	const char buf[] = "foo";
64 	int fd, res;
65 
66 	fd = openat(dfd, fn, OPEN_FLAGS, OPEN_MODE);
67 	if (fd < 0) {
68 		fprintf(stderr, "prepare/open: %s\n", strerror(errno));
69 		return -1;
70 	}
71 
72 	res = pwrite(fd, buf, sizeof(buf), 1ull << 32);
73 	if (res < 0)
74 		fprintf(stderr, "prepare/pwrite: %s\n", strerror(errno));
75 
76 	close(fd);
77 	return res < 0 ? res : 0;
78 }
79 
test_linked_files(int dfd,const char * fn,bool async)80 static int test_linked_files(int dfd, const char *fn, bool async)
81 {
82 	struct io_uring ring;
83 	struct io_uring_sqe *sqe;
84 	char buffer[128];
85 	struct iovec iov = {.iov_base = buffer, .iov_len = sizeof(buffer), };
86 	int ret, fd;
87 	int fds[2];
88 
89 	ret = io_uring_queue_init(10, &ring, 0);
90 	if (ret < 0)
91 		DIE("failed to init io_uring: %s\n", strerror(-ret));
92 
93 	if (pipe(fds)) {
94 		perror("pipe");
95 		return 1;
96 	}
97 
98 	sqe = io_uring_get_sqe(&ring);
99 	if (!sqe) {
100 		printf("get sqe failed\n");
101 		return -1;
102 	}
103 	io_uring_prep_readv(sqe, fds[0], &iov, 1, 0);
104 	sqe->flags |= IOSQE_IO_LINK;
105 	if (async)
106 		sqe->flags |= IOSQE_ASYNC;
107 
108 	sqe = io_uring_get_sqe(&ring);
109 	if (!sqe) {
110 		fprintf(stderr, "failed to get sqe\n");
111 		return 1;
112 	}
113 	io_uring_prep_openat(sqe, dfd, fn, OPEN_FLAGS, OPEN_MODE);
114 
115 	ret = io_uring_submit(&ring);
116 	if (ret != 2) {
117 		fprintf(stderr, "failed to submit openat: %s\n", strerror(-ret));
118 		return 1;
119 	}
120 
121 	fd = dup(ring.ring_fd);
122 	if (fd < 0) {
123 		fprintf(stderr, "dup() failed: %s\n", strerror(-fd));
124 		return 1;
125 	}
126 
127 	/* io_uring->flush() */
128 	close(fd);
129 
130 	io_uring_queue_exit(&ring);
131 	return 0;
132 }
133 
test_drained_files(int dfd,const char * fn,bool linked,bool prepend)134 static int test_drained_files(int dfd, const char *fn, bool linked, bool prepend)
135 {
136 	struct io_uring ring;
137 	struct io_uring_sqe *sqe;
138 	char buffer[128];
139 	struct iovec iov = {.iov_base = buffer, .iov_len = sizeof(buffer), };
140 	int ret, fd, fds[2], to_cancel = 0;
141 
142 	ret = io_uring_queue_init(10, &ring, 0);
143 	if (ret < 0)
144 		DIE("failed to init io_uring: %s\n", strerror(-ret));
145 
146 	if (pipe(fds)) {
147 		perror("pipe");
148 		return 1;
149 	}
150 
151 	sqe = io_uring_get_sqe(&ring);
152 	if (!sqe) {
153 		printf("get sqe failed\n");
154 		return -1;
155 	}
156 	io_uring_prep_readv(sqe, fds[0], &iov, 1, 0);
157 	sqe->user_data = 0;
158 
159 	if (prepend) {
160 		sqe = io_uring_get_sqe(&ring);
161 		if (!sqe) {
162 			fprintf(stderr, "failed to get sqe\n");
163 			return 1;
164 		}
165 		io_uring_prep_nop(sqe);
166 		sqe->flags |= IOSQE_IO_DRAIN;
167 		to_cancel++;
168 		sqe->user_data = to_cancel;
169 	}
170 
171 	if (linked) {
172 		sqe = io_uring_get_sqe(&ring);
173 		if (!sqe) {
174 			fprintf(stderr, "failed to get sqe\n");
175 			return 1;
176 		}
177 		io_uring_prep_nop(sqe);
178 		sqe->flags |= IOSQE_IO_DRAIN | IOSQE_IO_LINK;
179 		to_cancel++;
180 		sqe->user_data = to_cancel;
181 	}
182 
183 	sqe = io_uring_get_sqe(&ring);
184 	if (!sqe) {
185 		fprintf(stderr, "failed to get sqe\n");
186 		return 1;
187 	}
188 	io_uring_prep_openat(sqe, dfd, fn, OPEN_FLAGS, OPEN_MODE);
189 	sqe->flags |= IOSQE_IO_DRAIN;
190 	to_cancel++;
191 	sqe->user_data = to_cancel;
192 
193 
194 	ret = io_uring_submit(&ring);
195 	if (ret != 1 + to_cancel) {
196 		fprintf(stderr, "failed to submit openat: %s\n", strerror(-ret));
197 		return 1;
198 	}
199 
200 	fd = dup(ring.ring_fd);
201 	if (fd < 0) {
202 		fprintf(stderr, "dup() failed: %s\n", strerror(-fd));
203 		return 1;
204 	}
205 
206 	/*
207 	 * close(), which triggers ->flush(), and io_uring_queue_exit()
208 	 * should successfully return and not hang.
209 	 */
210 	close(fd);
211 	io_uring_queue_exit(&ring);
212 	return 0;
213 }
214 
main(int argc,char * argv[])215 int main(int argc, char *argv[])
216 {
217 	const char *fn = "io_uring_openat_test";
218 	struct io_uring ring;
219 	int ret, dfd;
220 
221 	if (argc > 1)
222 		return 0;
223 
224 	dfd = open("/tmp", O_PATH);
225 	if (dfd < 0)
226 		DIE("open /tmp: %s\n", strerror(errno));
227 
228 	ret = io_uring_queue_init(RSIZE, &ring, 0);
229 	if (ret < 0)
230 		DIE("failed to init io_uring: %s\n", strerror(-ret));
231 
232 	if (prepare_file(dfd, fn))
233 		return 1;
234 
235 	ret = open_io_uring(&ring, dfd, fn);
236 	if (ret) {
237 		fprintf(stderr, "open_io_uring() failed\n");
238 		goto out;
239 	}
240 
241 	ret = test_linked_files(dfd, fn, false);
242 	if (ret) {
243 		fprintf(stderr, "test_linked_files() !async failed\n");
244 		goto out;
245 	}
246 
247 	ret = test_linked_files(dfd, fn, true);
248 	if (ret) {
249 		fprintf(stderr, "test_linked_files() async failed\n");
250 		goto out;
251 	}
252 
253 	ret = test_drained_files(dfd, fn, false, false);
254 	if (ret) {
255 		fprintf(stderr, "test_drained_files() failed\n");
256 		goto out;
257 	}
258 
259 	ret = test_drained_files(dfd, fn, false, true);
260 	if (ret) {
261 		fprintf(stderr, "test_drained_files() middle failed\n");
262 		goto out;
263 	}
264 
265 	ret = test_drained_files(dfd, fn, true, false);
266 	if (ret) {
267 		fprintf(stderr, "test_drained_files() linked failed\n");
268 		goto out;
269 	}
270 out:
271 	io_uring_queue_exit(&ring);
272 	close(dfd);
273 	unlink("/tmp/io_uring_openat_test");
274 	return ret;
275 }
276