• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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("testfile", O_WRONLY | O_CREAT, 0644);
67 	if (fd < 0) {
68 		perror("open");
69 		return 1;
70 	}
71 
72 	for (i = 0; i < 4; i++) {
73 		iovecs[i].iov_base = t_malloc(4096);
74 		iovecs[i].iov_len = 4096;
75 	}
76 
77 	off = 0;
78 	for (i = 0; i < 4; i++) {
79 		sqe = io_uring_get_sqe(ring);
80 		if (!sqe) {
81 			fprintf(stderr, "get sqe failed\n");
82 			goto err;
83 		}
84 
85 		io_uring_prep_writev(sqe, fd, &iovecs[i], 1, off);
86 		sqe->user_data = 0;
87 		off += 4096;
88 	}
89 
90 	sqe = io_uring_get_sqe(ring);
91 	if (!sqe) {
92 		fprintf(stderr, "get sqe failed\n");
93 		goto err;
94 	}
95 
96 	io_uring_prep_fsync(sqe, fd, IORING_FSYNC_DATASYNC);
97 	sqe->user_data = 1;
98 	io_uring_sqe_set_flags(sqe, IOSQE_IO_DRAIN);
99 
100 	ret = io_uring_submit(ring);
101 	if (ret < 0) {
102 		fprintf(stderr, "sqe submit failed: %d\n", ret);
103 		goto err;
104 	} else if (ret < 5) {
105 		fprintf(stderr, "Submitted only %d\n", ret);
106 		goto err;
107 	}
108 
109 	for (i = 0; i < 5; i++) {
110 		ret = io_uring_wait_cqe(ring, &cqe);
111 		if (ret < 0) {
112 			fprintf(stderr, "wait completion %d\n", ret);
113 			goto err;
114 		}
115 		/* kernel doesn't support IOSQE_IO_DRAIN */
116 		if (cqe->res == -EINVAL)
117 			break;
118 		if (i <= 3) {
119 			if (cqe->user_data) {
120 				fprintf(stderr, "Got fsync early?\n");
121 				goto err;
122 			}
123 		} else {
124 			if (!cqe->user_data) {
125 				fprintf(stderr, "Got write late?\n");
126 				goto err;
127 			}
128 		}
129 		io_uring_cqe_seen(ring, cqe);
130 	}
131 
132 	unlink("testfile");
133 	return 0;
134 err:
135 	unlink("testfile");
136 	return 1;
137 }
138 
139 #define FILE_SIZE 1024
140 
test_sync_file_range(struct io_uring * ring)141 static int test_sync_file_range(struct io_uring *ring)
142 {
143 	int ret, fd, save_errno;
144 	struct io_uring_sqe *sqe;
145 	struct io_uring_cqe *cqe;
146 
147 	t_create_file(".sync_file_range", FILE_SIZE);
148 
149 	fd = open(".sync_file_range", O_RDWR);
150 	save_errno = errno;
151 	unlink(".sync_file_range");
152 	errno = save_errno;
153 	if (fd < 0) {
154 		perror("file open");
155 		return 1;
156 	}
157 
158 	sqe = io_uring_get_sqe(ring);
159 	if (!sqe) {
160 		fprintf(stderr, "sqe get failed\n");
161 		return 1;
162 	}
163 	io_uring_prep_sync_file_range(sqe, fd, 0, 0, 0);
164 	sqe->user_data = 1;
165 
166 	ret = io_uring_submit(ring);
167 	if (ret != 1) {
168 		fprintf(stderr, "submit failed: %d\n", ret);
169 		return 1;
170 	}
171 	ret = io_uring_wait_cqe(ring, &cqe);
172 	if (ret) {
173 		fprintf(stderr, "wait_cqe failed: %d\n", ret);
174 		return 1;
175 	}
176 	if (cqe->res) {
177 		fprintf(stderr, "sfr failed: %d\n", cqe->res);
178 		return 1;
179 	}
180 
181 	io_uring_cqe_seen(ring, cqe);
182 	return 0;
183 }
184 
main(int argc,char * argv[])185 int main(int argc, char *argv[])
186 {
187 	struct io_uring ring;
188 	int ret;
189 
190 	if (argc > 1)
191 		return 0;
192 
193 	ret = io_uring_queue_init(8, &ring, 0);
194 	if (ret) {
195 		fprintf(stderr, "ring setup failed\n");
196 		return 1;
197 
198 	}
199 
200 	ret = test_single_fsync(&ring);
201 	if (ret) {
202 		fprintf(stderr, "test_single_fsync failed\n");
203 		return ret;
204 	}
205 
206 	ret = test_barrier_fsync(&ring);
207 	if (ret) {
208 		fprintf(stderr, "test_barrier_fsync failed\n");
209 		return ret;
210 	}
211 
212 	ret = test_sync_file_range(&ring);
213 	if (ret) {
214 		fprintf(stderr, "test_sync_file_range failed\n");
215 		return ret;
216 	}
217 
218 	return 0;
219 }
220