Changeset View
Changeset View
Standalone View
Standalone View
tests/sys/file/fspacectl_test.c
- This file was added.
/*- | |||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2021 The FreeBSD Foundation | |||||
* All rights reserved. | |||||
* | |||||
lwhsu: this line is not needed. | |||||
* This software was developed by Ka Ho Ng under sponsorship from | |||||
* the FreeBSD Foundation. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
*/ | |||||
#include <sys/param.h> | |||||
#include <sys/mount.h> | |||||
#include <sys/stat.h> | |||||
#include <atf-c.h> | |||||
#include <fcntl.h> | |||||
#include <malloc.h> | |||||
static off_t file_max_blocks = 32; | |||||
static const char byte_to_fill = 0x5f; | |||||
static int | |||||
fill(int fd, off_t offset, off_t len) | |||||
{ | |||||
int error; | |||||
size_t blen; | |||||
char *buf; | |||||
struct stat statbuf; | |||||
blksize_t blocksize; | |||||
if (fstat(fd, &statbuf) == -1) | |||||
return (1); | |||||
blocksize = statbuf.st_blksize; | |||||
error = 0; | |||||
buf = malloc(blocksize); | |||||
if (buf == NULL) | |||||
return (1); | |||||
while (len > 0) { | |||||
blen = len < (off_t)blocksize ? len : blocksize; | |||||
memset(buf, byte_to_fill, blen); | |||||
if (pwrite(fd, buf, blen, offset) != (ssize_t)blen) { | |||||
error = 1; | |||||
break; | |||||
} | |||||
len -= blen; | |||||
offset += blen; | |||||
} | |||||
free(buf); | |||||
return (error); | |||||
} | |||||
static blksize_t | |||||
fd_get_blksize(void) | |||||
{ | |||||
struct statfs statfsbuf; | |||||
if (statfs(".", &statfsbuf) == -1) | |||||
return (-1); | |||||
return statfsbuf.f_iosize; | |||||
} | |||||
static int | |||||
check_content_dealloc(int fd, off_t hole_start, off_t hole_len, off_t file_sz) | |||||
{ | |||||
int error; | |||||
size_t blen; | |||||
off_t offset, resid; | |||||
struct stat statbuf; | |||||
char *buf, *sblk; | |||||
blksize_t blocksize; | |||||
blocksize = fd_get_blksize(); | |||||
if (blocksize == -1) | |||||
return (1); | |||||
error = 0; | |||||
buf = malloc(blocksize * 2); | |||||
if (buf == NULL) | |||||
return (1); | |||||
sblk = buf + blocksize; | |||||
memset(sblk, 0, blocksize); | |||||
if ((uint64_t)hole_start + hole_len > (uint64_t)file_sz) | |||||
hole_len = file_sz - hole_start; | |||||
/* | |||||
* Check hole is zeroed. | |||||
*/ | |||||
offset = hole_start; | |||||
resid = hole_len; | |||||
while (resid > 0) { | |||||
blen = resid < (off_t)blocksize ? resid : blocksize; | |||||
if (pread(fd, buf, blen, offset) != (ssize_t)blen) { | |||||
error = 1; | |||||
break; | |||||
} | |||||
if (memcmp(buf, sblk, blen) != 0) { | |||||
error = 1; | |||||
break; | |||||
} | |||||
resid -= blen; | |||||
offset += blen; | |||||
} | |||||
memset(sblk, byte_to_fill, blocksize); | |||||
/* | |||||
* Check file region before hole is zeroed. | |||||
*/ | |||||
offset = 0; | |||||
resid = hole_start; | |||||
while (resid > 0) { | |||||
blen = resid < (off_t)blocksize ? resid : blocksize; | |||||
if (pread(fd, buf, blen, offset) != (ssize_t)blen) { | |||||
error = 1; | |||||
break; | |||||
} | |||||
if (memcmp(buf, sblk, blen) != 0) { | |||||
error = 1; | |||||
break; | |||||
} | |||||
resid -= blen; | |||||
offset += blen; | |||||
} | |||||
/* | |||||
* Check file region after hole is zeroed. | |||||
*/ | |||||
offset = hole_start + hole_len; | |||||
resid = file_sz - offset; | |||||
while (resid > 0) { | |||||
blen = resid < (off_t)blocksize ? resid : blocksize; | |||||
if (pread(fd, buf, blen, offset) != (ssize_t)blen) { | |||||
error = 1; | |||||
break; | |||||
} | |||||
if (memcmp(buf, sblk, blen) != 0) { | |||||
error = 1; | |||||
break; | |||||
} | |||||
resid -= blen; | |||||
offset += blen; | |||||
} | |||||
/* | |||||
* Check file size matches with expected file size. | |||||
*/ | |||||
if (fstat(fd, &statbuf) == -1) | |||||
error = -1; | |||||
if (statbuf.st_size != file_sz) | |||||
error = -1; | |||||
free(buf); | |||||
return (error); | |||||
} | |||||
/* | |||||
* Check aligned deallocation | |||||
*/ | |||||
ATF_TC_WITHOUT_HEAD(aligned_dealloc); | |||||
ATF_TC_BODY(aligned_dealloc, tc) | |||||
{ | |||||
struct spacectl_range range; | |||||
off_t offset, length; | |||||
blksize_t blocksize; | |||||
int fd; | |||||
ATF_REQUIRE((blocksize = fd_get_blksize()) != -1); | |||||
range.r_offset = offset = blocksize; | |||||
range.r_len = length = (file_max_blocks - 1) * blocksize - | |||||
range.r_offset; | |||||
ATF_REQUIRE((fd = open("sys_fspacectl_testfile", | |||||
O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1); | |||||
ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0); | |||||
ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0); | |||||
ATF_CHECK(check_content_dealloc(fd, offset, length, | |||||
file_max_blocks * blocksize) == 0); | |||||
ATF_REQUIRE(close(fd) == 0); | |||||
} | |||||
/* | |||||
* Check unaligned deallocation | |||||
*/ | |||||
ATF_TC_WITHOUT_HEAD(unaligned_dealloc); | |||||
ATF_TC_BODY(unaligned_dealloc, tc) | |||||
{ | |||||
struct spacectl_range range; | |||||
off_t offset, length; | |||||
blksize_t blocksize; | |||||
int fd; | |||||
ATF_REQUIRE((blocksize = fd_get_blksize()) != -1); | |||||
range.r_offset = offset = blocksize / 2; | |||||
range.r_len = length = (file_max_blocks - 1) * blocksize + | |||||
blocksize / 2 - offset; | |||||
ATF_REQUIRE((fd = open("sys_fspacectl_testfile", | |||||
O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1); | |||||
ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0); | |||||
ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0); | |||||
ATF_CHECK(check_content_dealloc(fd, offset, length, | |||||
file_max_blocks * blocksize) == 0); | |||||
ATF_REQUIRE(close(fd) == 0); | |||||
} | |||||
/* | |||||
* Check aligned deallocation from certain offset to OFF_MAX | |||||
*/ | |||||
ATF_TC_WITHOUT_HEAD(aligned_dealloc_offmax); | |||||
ATF_TC_BODY(aligned_dealloc_offmax, tc) | |||||
{ | |||||
struct spacectl_range range; | |||||
off_t offset, length; | |||||
blksize_t blocksize; | |||||
int fd; | |||||
ATF_REQUIRE((blocksize = fd_get_blksize()) != -1); | |||||
range.r_offset = offset = blocksize; | |||||
range.r_len = length = OFF_MAX - offset; | |||||
ATF_REQUIRE((fd = open("sys_fspacectl_testfile", | |||||
O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1); | |||||
ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0); | |||||
ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0); | |||||
ATF_CHECK(check_content_dealloc(fd, offset, length, | |||||
file_max_blocks * blocksize) == 0); | |||||
ATF_REQUIRE(close(fd) == 0); | |||||
} | |||||
/* | |||||
* Check unaligned deallocation from certain offset to OFF_MAX | |||||
*/ | |||||
ATF_TC_WITHOUT_HEAD(unaligned_dealloc_offmax); | |||||
ATF_TC_BODY(unaligned_dealloc_offmax, tc) | |||||
{ | |||||
struct spacectl_range range; | |||||
off_t offset, length; | |||||
blksize_t blocksize; | |||||
int fd; | |||||
ATF_REQUIRE((blocksize = fd_get_blksize()) != -1); | |||||
range.r_offset = offset = blocksize / 2; | |||||
range.r_len = length = OFF_MAX - offset; | |||||
ATF_REQUIRE((fd = open("sys_fspacectl_testfile", | |||||
O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1); | |||||
ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0); | |||||
ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0); | |||||
ATF_CHECK(check_content_dealloc(fd, offset, length, | |||||
file_max_blocks * blocksize) == 0); | |||||
ATF_REQUIRE(close(fd) == 0); | |||||
} | |||||
/* | |||||
* Check aligned deallocation around EOF | |||||
*/ | |||||
ATF_TC_WITHOUT_HEAD(aligned_dealloc_eof); | |||||
ATF_TC_BODY(aligned_dealloc_eof, tc) | |||||
{ | |||||
struct spacectl_range range; | |||||
off_t offset, length; | |||||
blksize_t blocksize; | |||||
int fd; | |||||
ATF_REQUIRE((blocksize = fd_get_blksize()) != -1); | |||||
range.r_offset = offset = blocksize; | |||||
range.r_len = length = (file_max_blocks + 1) * blocksize - | |||||
range.r_offset; | |||||
ATF_REQUIRE((fd = open("sys_fspacectl_testfile", | |||||
O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1); | |||||
Done Inline ActionsTODO: Add also SPACECTL_ALLOC khng: TODO: Add also SPACECTL_ALLOC | |||||
Done Inline ActionsDone in D28833. khng: Done in D28833. | |||||
ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0); | |||||
ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0); | |||||
ATF_CHECK(check_content_dealloc(fd, offset, length, | |||||
file_max_blocks * blocksize) == 0); | |||||
ATF_REQUIRE(close(fd) == 0); | |||||
} | |||||
/* | |||||
* Check unaligned deallocation around EOF | |||||
*/ | |||||
ATF_TC_WITHOUT_HEAD(unaligned_dealloc_eof); | |||||
ATF_TC_BODY(unaligned_dealloc_eof, tc) | |||||
{ | |||||
struct spacectl_range range; | |||||
off_t offset, length; | |||||
blksize_t blocksize; | |||||
int fd; | |||||
ATF_REQUIRE((blocksize = fd_get_blksize()) != -1); | |||||
range.r_offset = offset = blocksize / 2; | |||||
range.r_len = length = file_max_blocks * blocksize + blocksize / 2 - | |||||
range.r_offset; | |||||
ATF_REQUIRE((fd = open("sys_fspacectl_testfile", | |||||
O_CREAT | O_RDWR | O_TRUNC, 0600)) != -1); | |||||
ATF_REQUIRE(fill(fd, 0, file_max_blocks * blocksize) == 0); | |||||
ATF_CHECK(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0); | |||||
ATF_CHECK(check_content_dealloc(fd, offset, length, | |||||
file_max_blocks * blocksize) == 0); | |||||
ATF_REQUIRE(close(fd) == 0); | |||||
} | |||||
ATF_TP_ADD_TCS(tp) | |||||
{ | |||||
ATF_TP_ADD_TC(tp, aligned_dealloc); | |||||
ATF_TP_ADD_TC(tp, unaligned_dealloc); | |||||
ATF_TP_ADD_TC(tp, aligned_dealloc_eof); | |||||
ATF_TP_ADD_TC(tp, unaligned_dealloc_eof); | |||||
ATF_TP_ADD_TC(tp, aligned_dealloc_offmax); | |||||
ATF_TP_ADD_TC(tp, unaligned_dealloc_offmax); | |||||
return atf_no_error(); | |||||
} |
this line is not needed.