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