]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/file/fspacectl_test.c
Add 'contrib/libdiff/' from commit '9eb461aa4b61ab47855b2cee9e5b626a76888b5e'
[FreeBSD/FreeBSD.git] / tests / sys / file / fspacectl_test.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * This software was developed by Ka Ho Ng under sponsorship from
8  * the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/param.h>
33 #include <sys/mount.h>
34 #include <sys/stat.h>
35
36 #include <atf-c.h>
37 #include <fcntl.h>
38 #include <malloc.h>
39
40 static off_t file_max_blocks = 32;
41 static const char byte_to_fill = 0x5f;
42
43 static int
44 fill(int fd, off_t offset, off_t len)
45 {
46         int error;
47         size_t blen;
48         char *buf;
49         struct stat statbuf;
50         blksize_t blocksize;
51
52         if (fstat(fd, &statbuf) == -1)
53                 return (1);
54         blocksize = statbuf.st_blksize;
55         error = 0;
56         buf = malloc(blocksize);
57         if (buf == NULL)
58                 return (1);
59
60         while (len > 0) {
61                 blen = len < (off_t)blocksize ? len : blocksize;
62                 memset(buf, byte_to_fill, blen);
63                 if (pwrite(fd, buf, blen, offset) != (ssize_t)blen) {
64                         error = 1;
65                         break;
66                 }
67                 len -= blen;
68                 offset += blen;
69         }
70
71         free(buf);
72         return (error);
73 }
74
75 static blksize_t
76 fd_get_blksize(void)
77 {
78         struct statfs statfsbuf;
79
80         if (statfs(".", &statfsbuf) == -1)
81                 return (-1);
82         return statfsbuf.f_iosize;
83 }
84
85 static int
86 check_content_dealloc(int fd, off_t hole_start, off_t hole_len, off_t file_sz)
87 {
88         int error;
89         size_t blen;
90         off_t offset, resid;
91         struct stat statbuf;
92         char *buf, *sblk;
93         blksize_t blocksize;
94
95         blocksize = fd_get_blksize();
96         if (blocksize == -1)
97                 return (1);
98         error = 0;
99         buf = malloc(blocksize * 2);
100         if (buf == NULL)
101                 return (1);
102         sblk = buf + blocksize;
103
104         memset(sblk, 0, blocksize);
105
106         if ((uint64_t)hole_start + hole_len > (uint64_t)file_sz)
107                 hole_len = file_sz - hole_start;
108
109         /*
110          * Check hole is zeroed.
111          */
112         offset = hole_start;
113         resid = hole_len;
114         while (resid > 0) {
115                 blen = resid < (off_t)blocksize ? resid : blocksize;
116                 if (pread(fd, buf, blen, offset) != (ssize_t)blen) {
117                         error = 1;
118                         break;
119                 }
120                 if (memcmp(buf, sblk, blen) != 0) {
121                         error = 1;
122                         break;
123                 }
124                 resid -= blen;
125                 offset += blen;
126         }
127
128         memset(sblk, byte_to_fill, blocksize);
129
130         /*
131          * Check file region before hole is zeroed.
132          */
133         offset = 0;
134         resid = hole_start;
135         while (resid > 0) {
136                 blen = resid < (off_t)blocksize ? resid : blocksize;
137                 if (pread(fd, buf, blen, offset) != (ssize_t)blen) {
138                         error = 1;
139                         break;
140                 }
141                 if (memcmp(buf, sblk, blen) != 0) {
142                         error = 1;
143                         break;
144                 }
145                 resid -= blen;
146                 offset += blen;
147         }
148
149         /*
150          * Check file region after hole is zeroed.
151          */
152         offset = hole_start + hole_len;
153         resid = file_sz - offset;
154         while (resid > 0) {
155                 blen = resid < (off_t)blocksize ? resid : blocksize;
156                 if (pread(fd, buf, blen, offset) != (ssize_t)blen) {
157                         error = 1;
158                         break;
159                 }
160                 if (memcmp(buf, sblk, blen) != 0) {
161                         error = 1;
162                         break;
163                 }
164                 resid -= blen;
165                 offset += blen;
166         }
167
168         /*
169          * Check file size matches with expected file size.
170          */
171         if (fstat(fd, &statbuf) == -1)
172                 error = -1;
173         if (statbuf.st_size != file_sz)
174                 error = -1;
175
176         free(buf);
177         return (error);
178 }
179
180 /*
181  * Check aligned deallocation
182  */
183 ATF_TC_WITHOUT_HEAD(aligned_dealloc);
184 ATF_TC_BODY(aligned_dealloc, tc)
185 {
186         struct spacectl_range range;
187         off_t offset, length;
188         blksize_t blocksize;
189         int fd;
190
191         ATF_REQUIRE((blocksize = fd_get_blksize()) != -1);
192         range.r_offset = offset = blocksize;
193         range.r_len = length = (file_max_blocks - 1) * blocksize -
194             range.r_offset;
195
196         ATF_REQUIRE((fd = open("sys_fspacectl_testfile",
197                          O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1);
198         ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0);
199         ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0);
200         ATF_CHECK(check_content_dealloc(fd, offset, length,
201                       file_max_blocks * blocksize) == 0);
202         ATF_REQUIRE(close(fd) == 0);
203 }
204
205 /*
206  * Check unaligned deallocation
207  */
208 ATF_TC_WITHOUT_HEAD(unaligned_dealloc);
209 ATF_TC_BODY(unaligned_dealloc, tc)
210 {
211         struct spacectl_range range;
212         off_t offset, length;
213         blksize_t blocksize;
214         int fd;
215
216         ATF_REQUIRE((blocksize = fd_get_blksize()) != -1);
217         range.r_offset = offset = blocksize / 2;
218         range.r_len = length = (file_max_blocks - 1) * blocksize +
219             blocksize / 2 - offset;
220
221         ATF_REQUIRE((fd = open("sys_fspacectl_testfile",
222                          O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1);
223         ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0);
224         ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0);
225         ATF_CHECK(check_content_dealloc(fd, offset, length,
226                       file_max_blocks * blocksize) == 0);
227         ATF_REQUIRE(close(fd) == 0);
228 }
229
230 /*
231  * Check aligned deallocation from certain offset to OFF_MAX
232  */
233 ATF_TC_WITHOUT_HEAD(aligned_dealloc_offmax);
234 ATF_TC_BODY(aligned_dealloc_offmax, tc)
235 {
236         struct spacectl_range range;
237         off_t offset, length;
238         blksize_t blocksize;
239         int fd;
240
241         ATF_REQUIRE((blocksize = fd_get_blksize()) != -1);
242         range.r_offset = offset = blocksize;
243         range.r_len = length = OFF_MAX - offset;
244
245         ATF_REQUIRE((fd = open("sys_fspacectl_testfile",
246                          O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1);
247         ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0);
248         ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0);
249         ATF_CHECK(check_content_dealloc(fd, offset, length,
250                       file_max_blocks * blocksize) == 0);
251         ATF_REQUIRE(close(fd) == 0);
252 }
253
254 /*
255  * Check unaligned deallocation from certain offset to OFF_MAX
256  */
257 ATF_TC_WITHOUT_HEAD(unaligned_dealloc_offmax);
258 ATF_TC_BODY(unaligned_dealloc_offmax, tc)
259 {
260         struct spacectl_range range;
261         off_t offset, length;
262         blksize_t blocksize;
263         int fd;
264
265         ATF_REQUIRE((blocksize = fd_get_blksize()) != -1);
266         range.r_offset = offset = blocksize / 2;
267         range.r_len = length = OFF_MAX - offset;
268
269         ATF_REQUIRE((fd = open("sys_fspacectl_testfile",
270                          O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1);
271         ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0);
272         ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0);
273         ATF_CHECK(check_content_dealloc(fd, offset, length,
274                       file_max_blocks * blocksize) == 0);
275         ATF_REQUIRE(close(fd) == 0);
276 }
277
278 /*
279  * Check aligned deallocation around EOF
280  */
281 ATF_TC_WITHOUT_HEAD(aligned_dealloc_eof);
282 ATF_TC_BODY(aligned_dealloc_eof, tc)
283 {
284         struct spacectl_range range;
285         off_t offset, length;
286         blksize_t blocksize;
287         int fd;
288
289         ATF_REQUIRE((blocksize = fd_get_blksize()) != -1);
290         range.r_offset = offset = blocksize;
291         range.r_len = length = (file_max_blocks + 1) * blocksize -
292             range.r_offset;
293
294         ATF_REQUIRE((fd = open("sys_fspacectl_testfile",
295                          O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1);
296         ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0);
297         ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0);
298         ATF_CHECK(check_content_dealloc(fd, offset, length,
299                       file_max_blocks * blocksize) == 0);
300         ATF_REQUIRE(close(fd) == 0);
301 }
302
303 /*
304  * Check unaligned deallocation around EOF
305  */
306 ATF_TC_WITHOUT_HEAD(unaligned_dealloc_eof);
307 ATF_TC_BODY(unaligned_dealloc_eof, tc)
308 {
309         struct spacectl_range range;
310         off_t offset, length;
311         blksize_t blocksize;
312         int fd;
313
314         ATF_REQUIRE((blocksize = fd_get_blksize()) != -1);
315         range.r_offset = offset = blocksize / 2;
316         range.r_len = length = file_max_blocks * blocksize + blocksize / 2 -
317             range.r_offset;
318
319         ATF_REQUIRE((fd = open("sys_fspacectl_testfile",
320                          O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1);
321         ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0);
322         ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0);
323         ATF_CHECK(check_content_dealloc(fd, offset, length,
324                       file_max_blocks * blocksize) == 0);
325         ATF_REQUIRE(close(fd) == 0);
326 }
327
328 ATF_TP_ADD_TCS(tp)
329 {
330         ATF_TP_ADD_TC(tp, aligned_dealloc);
331         ATF_TP_ADD_TC(tp, unaligned_dealloc);
332         ATF_TP_ADD_TC(tp, aligned_dealloc_eof);
333         ATF_TP_ADD_TC(tp, unaligned_dealloc_eof);
334         ATF_TP_ADD_TC(tp, aligned_dealloc_offmax);
335         ATF_TP_ADD_TC(tp, unaligned_dealloc_offmax);
336
337         return atf_no_error();
338 }