xref: /aosp_15_r20/external/liburing/test/fsync.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: test io_uring fsync handling
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 "helpers.h"
14 #include "liburing.h"
15 
test_single_fsync(struct io_uring * ring)16 static int test_single_fsync(struct io_uring *ring)
17 {
18 	struct io_uring_cqe *cqe;
19 	struct io_uring_sqe *sqe;
20 	char buf[32];
21 	int fd, ret;
22 
23 	sprintf(buf, "./XXXXXX");
24 	fd = mkstemp(buf);
25 	if (fd < 0) {
26 		perror("open");
27 		return 1;
28 	}
29 
30 	sqe = io_uring_get_sqe(ring);
31 	if (!sqe) {
32 		fprintf(stderr, "get sqe failed\n");
33 		goto err;
34 	}
35 
36 	io_uring_prep_fsync(sqe, fd, 0);
37 
38 	ret = io_uring_submit(ring);
39 	if (ret <= 0) {
40 		fprintf(stderr, "sqe submit failed: %d\n", ret);
41 		goto err;
42 	}
43 
44 	ret = io_uring_wait_cqe(ring, &cqe);
45 	if (ret < 0) {
46 		fprintf(stderr, "wait completion %d\n", ret);
47 		goto err;
48 	}
49 
50 	io_uring_cqe_seen(ring, cqe);
51 	unlink(buf);
52 	return 0;
53 err:
54 	unlink(buf);
55 	return 1;
56 }
57 
test_barrier_fsync(struct io_uring * ring)58 static int test_barrier_fsync(struct io_uring *ring)
59 {
60 	struct io_uring_cqe *cqe;
61 	struct io_uring_sqe *sqe;
62 	struct iovec iovecs[4];
63 	int i, fd, ret;
64 	off_t off;
65 
66 	fd = open("fsync-testfile", O_WRONLY | O_CREAT, 0644);
67 	if (fd < 0) {
68 		perror("open");
69 		return 1;
70 	}
71 	unlink("fsync-testfile");
72 
73 	for (i = 0; i < ARRAY_SIZE(iovecs); i++) {
74 		iovecs[i].iov_base = t_malloc(4096);
75 		iovecs[i].iov_len = 4096;
76 	}
77 
78 	off = 0;
79 	for (i = 0; i < 4; i++) {
80 		sqe = io_uring_get_sqe(ring);
81 		if (!sqe) {
82 			fprintf(stderr, "get sqe failed\n");
83 			goto err;
84 		}
85 
86 		io_uring_prep_writev(sqe, fd, &iovecs[i], 1, off);
87 		sqe->user_data = 0;
88 		off += 4096;
89 	}
90 
91 	sqe = io_uring_get_sqe(ring);
92 	if (!sqe) {
93 		fprintf(stderr, "get sqe failed\n");
94 		goto err;
95 	}
96 
97 	io_uring_prep_fsync(sqe, fd, IORING_FSYNC_DATASYNC);
98 	sqe->user_data = 1;
99 	io_uring_sqe_set_flags(sqe, IOSQE_IO_DRAIN);
100 
101 	ret = io_uring_submit(ring);
102 	if (ret < 0) {
103 		fprintf(stderr, "sqe submit failed: %d\n", ret);
104 		goto err;
105 	} else if (ret < 5) {
106 		fprintf(stderr, "Submitted only %d\n", ret);
107 		goto err;
108 	}
109 
110 	for (i = 0; i < 5; i++) {
111 		ret = io_uring_wait_cqe(ring, &cqe);
112 		if (ret < 0) {
113 			fprintf(stderr, "wait completion %d\n", ret);
114 			goto err;
115 		}
116 		/* kernel doesn't support IOSQE_IO_DRAIN */
117 		if (cqe->res == -EINVAL)
118 			break;
119 		if (i <= 3) {
120 			if (cqe->user_data) {
121 				fprintf(stderr, "Got fsync early?\n");
122 				goto err;
123 			}
124 		} else {
125 			if (!cqe->user_data) {
126 				fprintf(stderr, "Got write late?\n");
127 				goto err;
128 			}
129 		}
130 		io_uring_cqe_seen(ring, cqe);
131 	}
132 
133 
134 	ret = 0;
135 	goto out;
136 err:
137 	ret = 1;
138 out:
139 	for (i = 0; i < ARRAY_SIZE(iovecs); i++)
140 		free(iovecs[i].iov_base);
141 	return ret;
142 }
143 
144 #define FILE_SIZE 1024
145 
test_sync_file_range(struct io_uring * ring)146 static int test_sync_file_range(struct io_uring *ring)
147 {
148 	int ret, fd, save_errno;
149 	struct io_uring_sqe *sqe;
150 	struct io_uring_cqe *cqe;
151 
152 	t_create_file(".sync_file_range", FILE_SIZE);
153 
154 	fd = open(".sync_file_range", O_RDWR);
155 	save_errno = errno;
156 	unlink(".sync_file_range");
157 	errno = save_errno;
158 	if (fd < 0) {
159 		perror("file open");
160 		return 1;
161 	}
162 
163 	sqe = io_uring_get_sqe(ring);
164 	if (!sqe) {
165 		fprintf(stderr, "sqe get failed\n");
166 		return 1;
167 	}
168 	io_uring_prep_sync_file_range(sqe, fd, 0, 0, 0);
169 	sqe->user_data = 1;
170 
171 	ret = io_uring_submit(ring);
172 	if (ret != 1) {
173 		fprintf(stderr, "submit failed: %d\n", ret);
174 		return 1;
175 	}
176 	ret = io_uring_wait_cqe(ring, &cqe);
177 	if (ret) {
178 		fprintf(stderr, "wait_cqe failed: %d\n", ret);
179 		return 1;
180 	}
181 	if (cqe->res) {
182 		fprintf(stderr, "sfr failed: %d\n", cqe->res);
183 		return 1;
184 	}
185 
186 	io_uring_cqe_seen(ring, cqe);
187 	return 0;
188 }
189 
main(int argc,char * argv[])190 int main(int argc, char *argv[])
191 {
192 	struct io_uring ring;
193 	int ret;
194 
195 	if (argc > 1)
196 		return 0;
197 
198 	ret = io_uring_queue_init(8, &ring, 0);
199 	if (ret) {
200 		fprintf(stderr, "ring setup failed\n");
201 		return 1;
202 
203 	}
204 
205 	ret = test_single_fsync(&ring);
206 	if (ret) {
207 		fprintf(stderr, "test_single_fsync failed\n");
208 		return ret;
209 	}
210 
211 	ret = test_barrier_fsync(&ring);
212 	if (ret) {
213 		fprintf(stderr, "test_barrier_fsync failed\n");
214 		return ret;
215 	}
216 
217 	ret = test_sync_file_range(&ring);
218 	if (ret) {
219 		fprintf(stderr, "test_sync_file_range failed\n");
220 		return ret;
221 	}
222 
223 	return 0;
224 }
225