1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: test io_uring fallocate
4 *
5 */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <sys/resource.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <fcntl.h>
15
16 #include "liburing.h"
17
18 static int no_fallocate;
19
test_fallocate_rlimit(struct io_uring * ring)20 static int test_fallocate_rlimit(struct io_uring *ring)
21 {
22 struct io_uring_cqe *cqe;
23 struct io_uring_sqe *sqe;
24 struct rlimit rlim;
25 char buf[32];
26 int fd, ret;
27
28 if (getrlimit(RLIMIT_FSIZE, &rlim) < 0) {
29 perror("getrlimit");
30 return 1;
31 }
32 rlim.rlim_cur = 64 * 1024;
33 rlim.rlim_max = 64 * 1024;
34 if (setrlimit(RLIMIT_FSIZE, &rlim) < 0) {
35 perror("setrlimit");
36 return 1;
37 }
38
39 sprintf(buf, "./XXXXXX");
40 fd = mkstemp(buf);
41 if (fd < 0) {
42 perror("open");
43 return 1;
44 }
45
46 sqe = io_uring_get_sqe(ring);
47 if (!sqe) {
48 fprintf(stderr, "get sqe failed\n");
49 goto err;
50 }
51 io_uring_prep_fallocate(sqe, fd, 0, 0, 128*1024);
52
53 ret = io_uring_submit(ring);
54 if (ret <= 0) {
55 fprintf(stderr, "sqe submit failed: %d\n", ret);
56 goto err;
57 }
58
59 ret = io_uring_wait_cqe(ring, &cqe);
60 if (ret < 0) {
61 fprintf(stderr, "wait completion %d\n", ret);
62 goto err;
63 }
64
65 if (cqe->res == -EINVAL) {
66 fprintf(stdout, "Fallocate not supported, skipping\n");
67 no_fallocate = 1;
68 goto out;
69 } else if (cqe->res != -EFBIG) {
70 fprintf(stderr, "Expected -EFBIG: %d\n", cqe->res);
71 goto err;
72 }
73 io_uring_cqe_seen(ring, cqe);
74 out:
75 unlink(buf);
76 return 0;
77 err:
78 unlink(buf);
79 return 1;
80 }
81
test_fallocate(struct io_uring * ring)82 static int test_fallocate(struct io_uring *ring)
83 {
84 struct io_uring_cqe *cqe;
85 struct io_uring_sqe *sqe;
86 struct stat st;
87 char buf[32];
88 int fd, ret;
89
90 sprintf(buf, "./XXXXXX");
91 fd = mkstemp(buf);
92 if (fd < 0) {
93 perror("open");
94 return 1;
95 }
96
97 sqe = io_uring_get_sqe(ring);
98 if (!sqe) {
99 fprintf(stderr, "get sqe failed\n");
100 goto err;
101 }
102 io_uring_prep_fallocate(sqe, fd, 0, 0, 128*1024);
103
104 ret = io_uring_submit(ring);
105 if (ret <= 0) {
106 fprintf(stderr, "sqe submit failed: %d\n", ret);
107 goto err;
108 }
109
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
116 if (cqe->res == -EINVAL) {
117 fprintf(stdout, "Fallocate not supported, skipping\n");
118 no_fallocate = 1;
119 goto out;
120 }
121 if (cqe->res) {
122 fprintf(stderr, "cqe->res=%d\n", cqe->res);
123 goto err;
124 }
125 io_uring_cqe_seen(ring, cqe);
126
127 if (fstat(fd, &st) < 0) {
128 perror("stat");
129 goto err;
130 }
131
132 if (st.st_size != 128*1024) {
133 fprintf(stderr, "Size mismatch: %llu\n",
134 (unsigned long long) st.st_size);
135 goto err;
136 }
137
138 out:
139 unlink(buf);
140 return 0;
141 err:
142 unlink(buf);
143 return 1;
144 }
145
test_fallocate_fsync(struct io_uring * ring)146 static int test_fallocate_fsync(struct io_uring *ring)
147 {
148 struct io_uring_cqe *cqe;
149 struct io_uring_sqe *sqe;
150 struct stat st;
151 char buf[32];
152 int fd, ret, i;
153
154 if (no_fallocate)
155 return 0;
156
157 sprintf(buf, "./XXXXXX");
158 fd = mkstemp(buf);
159 if (fd < 0) {
160 perror("open");
161 return 1;
162 }
163
164 sqe = io_uring_get_sqe(ring);
165 if (!sqe) {
166 fprintf(stderr, "get sqe failed\n");
167 goto err;
168 }
169 io_uring_prep_fallocate(sqe, fd, 0, 0, 128*1024);
170 sqe->flags |= IOSQE_IO_LINK;
171 sqe->user_data = 1;
172
173 sqe = io_uring_get_sqe(ring);
174 if (!sqe) {
175 fprintf(stderr, "get sqe failed\n");
176 goto err;
177 }
178 io_uring_prep_fsync(sqe, fd, 0);
179 sqe->user_data = 2;
180
181 ret = io_uring_submit(ring);
182 if (ret <= 0) {
183 fprintf(stderr, "sqe submit failed: %d\n", ret);
184 goto err;
185 }
186
187 for (i = 0; i < 2; i++) {
188 ret = io_uring_wait_cqe(ring, &cqe);
189 if (ret < 0) {
190 fprintf(stderr, "wait completion %d\n", ret);
191 goto err;
192 }
193 if (cqe->res) {
194 fprintf(stderr, "cqe->res=%d,data=%" PRIu64 "\n", cqe->res,
195 (uint64_t) cqe->user_data);
196 goto err;
197 }
198 io_uring_cqe_seen(ring, cqe);
199 }
200
201 if (fstat(fd, &st) < 0) {
202 perror("stat");
203 goto err;
204 }
205
206 if (st.st_size != 128*1024) {
207 fprintf(stderr, "Size mismatch: %llu\n",
208 (unsigned long long) st.st_size);
209 goto err;
210 }
211
212 unlink(buf);
213 return 0;
214 err:
215 unlink(buf);
216 return 1;
217 }
218
main(int argc,char * argv[])219 int main(int argc, char *argv[])
220 {
221 struct io_uring ring;
222 int ret;
223
224 if (argc > 1)
225 return 0;
226
227 ret = io_uring_queue_init(8, &ring, 0);
228 if (ret) {
229 fprintf(stderr, "ring setup failed\n");
230 return 1;
231 }
232
233 ret = test_fallocate(&ring);
234 if (ret) {
235 fprintf(stderr, "test_fallocate failed\n");
236 return ret;
237 }
238
239 ret = test_fallocate_fsync(&ring);
240 if (ret) {
241 fprintf(stderr, "test_fallocate_fsync failed\n");
242 return ret;
243 }
244
245 ret = test_fallocate_rlimit(&ring);
246 if (ret) {
247 fprintf(stderr, "test_fallocate_rlimit failed\n");
248 return ret;
249 }
250
251 return 0;
252 }
253