File: [Development] / xfs-cmds / xfstests / dmapi / src / suite2 / src / test_hole.c (download)
Revision 1.9, Wed Jun 18 16:09:09 2008 UTC (9 years, 4 months ago) by donaldd.longdrop.melbourne.sgi.com
Branch: MAIN
CVS Tags: HEAD Changes since 1.8: +16 -7
lines
fix XFSQA 145 / test_hole
There are two errors I see all the time in 145:
- dm_probe_hole returns EINVAL for offsets close to the file size
- dm_probe_hole wants EAGAIN for a probe at offset 1, length 0
The first error is a consequence of how the hole puching / probing
works. It always rounds the requested offset up to the next block
size and then checks if that rounded offset still fits into the file
size. Just do the same rounding in the testcase to make sure we don't
probe invalid offsets.
The second error is very odd to me, as we never return AGAIN in the
whole dm_probe_hole path. I've just commented it out.
I've also re-enabled the E2BIG to past-EOF test that was uncommented
before because it works perfectly fine now.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Merge of master-melb:xfs-cmds:31330a by kenmcd.
fix XFSQA 145 / test_hole
|
/*
* Copyright (c) 2000-2001 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <lib/hsm.h>
#include <lib/errtest.h>
#include <getopt.h>
#include <string.h>
/*---------------------------------------------------------------------------
Test program used to test the DMAPI function dm_punch_hole(). The
command line is:
test_hole [-v] [-s sid] pathname
where
ls_path
is the path to a specific copy of ls, important only for its size
pathname
is the path to the test filesystem
sid
is the session ID whose events you you are interested in.
----------------------------------------------------------------------------*/
#ifndef linux
extern char *sys_errlist[];
#endif
extern int optind;
extern char *optarg;
char *Progname;
static void
usage(void)
{
fprintf(stderr, "usage:\t%s [-v] [-s sid] ls_path directoryname\n",
Progname);
exit(1);
}
int
main(
int argc,
char **argv)
{
dm_sessid_t sid = DM_NO_SESSION;
char *pathname = NULL;
char *ls_path = NULL;
dm_off_t offset = 0, end;
dm_off_t ex_off = 0;
dm_extent_t extent[20];
u_int nelem;
dm_size_t length = 0;
void *hanp;
size_t hlen;
dm_token_t test_token;
char *name;
int opt;
int Vflag = 0;
char filename[128];
char command[128];
dm_off_t roff;
dm_size_t rlen;
dm_off_t blocksize = 5;
void *test_vp;
struct stat buf;
struct stat checkbuf;
if (Progname = strrchr(argv[0], '/')) {
Progname++;
} else {
Progname = argv[0];
}
/* Crack and validate the command line options. */
while ((opt = getopt(argc, argv, "vs:")) != EOF) {
switch (opt) {
case 'v':
Vflag++;
break;
case 's':
sid = atol(optarg);
break;
case '?':
usage();
}
}
if (optind + 2 != argc)
usage();
ls_path = argv[optind];
pathname = argv[optind+1];
if (dm_init_service(&name) == -1) {
fprintf(stdout, "Can't initialize the DMAPI\n");
exit(1);
}
if (sid == DM_NO_SESSION)
find_test_session(&sid);
/* Get the directory handle. */
if (dm_path_to_handle(pathname, &hanp, &hlen)) {
fprintf(stdout,
"ERROR: can't get handle for directory %s\n", pathname);
exit(1);
}
printf("Hole test beginning...\n");
sprintf(filename, "%s/VeryLongUnlikelyFilename.HOLETEST", pathname);
sprintf(command, "cp %s %s \n", ls_path, filename);
system(command);
if (dm_path_to_handle(filename, &hanp, &hlen)) {
fprintf(stdout, "can't get handle for %s\n; aborting test",
filename);
sprintf(command, "rm %s \n", filename);
system(command);
fprintf(stdout, "\tHole test aborted.\n");
dm_handle_free(hanp, hlen);
exit(1);
}
/* ## Get the block size using a length-1 probe. ## */
dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 1, 0,
&blocksize, &rlen);
if (blocksize==0) {
fprintf(stdout, "Error: block size appears to be 0!\n");
sprintf(command, "rm %s \n", filename);
system(command);
fprintf(stdout, "\tHole test aborted.\n");
dm_handle_free(hanp, hlen);
exit(1);
}
/*
* The kernel always rounds the offset up to the next block
* size, so we can only probes up to the previous to last block.
*/
end = (29604 / blocksize) * blocksize;
/* Check that dm_probe_hole returns an extent from the next
* highest multiple of the block size, to the end of the file
*/
for (offset = 0; offset < end; offset++) {
if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
&roff, &rlen)) {
fprintf(stdout, "dm_probe_hole failed on pass %lld (%s)\n",
(long long)offset, ERR_NAME);
}
else {
if (rlen != 0) {
fprintf(stdout,
"Error: hole did not extend to end of file!\n");
}
if (blocksize*(roff/blocksize) != roff) {
fprintf(stdout,
"Error: offset not a multiple of block size!\n");
}
}
}
/* Be sure dm_punch_hole doesn't change the time stamp,
* and verify that dm_get_allocinfo shows a hole
* followed by an extent to the end of the file.
*/
for(offset = 28672; offset > 0; offset-=blocksize) {
if (stat(filename, &buf)){
fprintf(stdout,
"Error: unable to stat the test file; %s (1st)\n",
filename);
continue;
}
if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
&roff, &rlen)) {
fprintf(stdout, "dm_probe_hole failed, %s\n",
ERR_NAME);
continue;
}
if (roff != offset) {
fprintf(stdout,
"Error: presumed offset was not %lld.\n",
(long long)(roff));
}
if (dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
roff, length)) {
fprintf(stdout, "dm_punch_hole failed, %s\n",
ERR_NAME);
continue;
}
if (stat(filename, &checkbuf)){
fprintf(stdout,
"Error: unable to stat the test file. (2nd)\n");
continue;
}
else {
/* COMPARE BUF AND CHECKBUF! */
#ifdef linux
if ((buf.st_atime == checkbuf.st_atime) &&
(buf.st_mtime == checkbuf.st_mtime) &&
(buf.st_ctime == checkbuf.st_ctime))
#else
if ((buf.st_atim.tv_sec == checkbuf.st_atim.tv_sec) &&
(buf.st_atim.tv_nsec == checkbuf.st_atim.tv_nsec) &&
(buf.st_mtim.tv_sec == checkbuf.st_mtim.tv_sec) &&
(buf.st_mtim.tv_nsec == checkbuf.st_mtim.tv_nsec) &&
(buf.st_ctim.tv_sec == checkbuf.st_ctim.tv_sec) &&
(buf.st_ctim.tv_nsec == checkbuf.st_ctim.tv_nsec))
#endif
{
if (Vflag) {
fprintf(stdout,
"\tTime stamp unchanged by hole from offset %lld.\n",
(long long)(offset));
}
}
else {
fprintf(stdout,
"Error: punch_hole changed file's time stamp.\n");
}
ex_off=0;
if ((dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN,
&ex_off, 1, extent, &nelem) == 1) &&
(extent->ex_type == DM_EXTENT_RES) &&
(dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN,
&ex_off, 1, extent, &nelem) == 0) &&
(extent->ex_type == DM_EXTENT_HOLE)) {
if (extent->ex_offset == roff){
if (Vflag) {
fprintf(stdout, "\tVerified hole at %lld\n",
(long long)(extent->ex_offset));
}
}
else {
fprintf(stdout, "\tError: get_allocinfo found hole at %lld\n",
(long long)(extent->ex_offset));
}
}
else {
fprintf(stdout, "\tError: get_allocinfo did not find an "
"extent followed by a hole!\n");
}
}
}
/*------------------------*\
|* ## Errno subtests ## *|
\*------------------------*/
fprintf(stdout, "\t(beginning errno subtests...)\n");
/*---------------------------------------------------------*/
ERRTEST(E2BIG,
"probe (from past EOF)",
dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 30000, length,
&roff, &rlen))
/*---------------------------------------------------------*/
ERRTEST(E2BIG,
"probe (to past EOF)",
dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 15000, 150000,
&roff, &rlen))
/*---------------------------------------------------------*/
SHAREDTEST("probe", hanp, hlen, test_token,
dm_probe_hole(sid, hanp, hlen, test_token,
0, 0, &roff, &rlen))
/*---------------------------------------------------------*/
EXCLTEST("punch", hanp, hlen, test_token,
dm_punch_hole(sid, hanp, hlen, test_token, 0, 0))
/*---------------------------------------------------------*/
/*
* No idea where that EAGAIN should come from, it's never
* returned from the kernel.
*
* -- hch
*/
#if 0
ERRTEST(EAGAIN,
"punch",
dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
1, length))
#endif
/*---------------------------------------------------------*/
if ((test_vp = handle_clone(hanp, hlen)) == NULL) {
fprintf(stderr,
"Cannot create a test handle (%s); skipping EBADF test\n",
ERR_NAME);
}
else {
((char *) test_vp)[hlen/2]++;
ERRTEST(EBADF,
"probe",
dm_probe_hole(sid, test_vp, hlen, DM_NO_TOKEN,
offset, length,
&roff, &rlen))
ERRTEST(EBADF,
"punch",
dm_punch_hole(sid, test_vp, hlen, DM_NO_TOKEN,
offset, length))
}
dm_handle_free(test_vp, hlen);
/*---------------------------------------------------------*/
ERRTEST(EFAULT,
"probe (null handle)",
dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
&roff, &rlen))
ERRTEST(EFAULT,
"probe (bad rlen)",
dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
&roff, (dm_size_t*)(-1000)))
ERRTEST(EFAULT,
"probe (bad roff)",
dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
(dm_off_t*)(-1000), &rlen))
/*---------------------------------------------------------*/
ERRTEST(EFAULT,
"punch",
dm_punch_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length))
/*---------------------------------------------------------*/
ERRTEST(EINVAL,
"probe (bad session)",
dm_probe_hole(-100, hanp, hlen, DM_NO_TOKEN, offset, length,
&roff, &rlen))
/*---------------------------------------------------------*/
ERRTEST(EINVAL,
"probe (bad token)",
dm_probe_hole(sid, hanp, hlen, 0, offset, length,
&roff, &rlen))
/*---------------------------------------------------------*/
ERRTEST(EINVAL,
"probe (bad token 2)",
dm_probe_hole(sid, hanp, hlen, 0, offset, length,
&roff, &rlen))
/*---------------------------------------------------------*/
fprintf(stdout, "\t(errno subtests complete)\n");
sprintf(command, "rm %s \n", filename);
system(command);
printf("Hole test complete.\n");
dm_handle_free(hanp, hlen);
exit(0);
}