Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/file/fspacectl_test.c
39536 views
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
}
339
340