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