|
|
@@ -61,15 +61,17 @@ int logcount = 0; /* total ops */ |
|
|
* be careful in how we select the different operations. The active operations |
|
|
* are mapped to numbers as follows: |
|
|
* |
|
|
* lite !lite |
|
|
* READ: 0 0 |
|
|
* WRITE: 1 1 |
|
|
* MAPREAD: 2 2 |
|
|
* MAPWRITE: 3 3 |
|
|
* TRUNCATE: - 4 |
|
|
* FALLOCATE: - 5 |
|
|
* PUNCH HOLE: - 6 |
|
|
* ZERO RANGE: - 7 |
|
|
* lite !lite integrity |
|
|
* READ: 0 0 0 |
|
|
* WRITE: 1 1 1 |
|
|
* MAPREAD: 2 2 2 |
|
|
* MAPWRITE: 3 3 3 |
|
|
* TRUNCATE: - 4 4 |
|
|
* FALLOCATE: - 5 5 |
|
|
* PUNCH HOLE: - 6 6 |
|
|
* ZERO RANGE: - 7 7 |
|
|
* COLLAPSE RANGE: - 8 8 |
|
|
* FSYNC: - - 9 |
|
|
* |
|
|
* When mapped read/writes are disabled, they are simply converted to normal |
|
|
* reads and writes. When fallocate/fpunch calls are disabled, they are |
|
|
@@ -98,6 +100,10 @@ int logcount = 0; /* total ops */ |
|
|
#define OP_INSERT_RANGE 9 |
|
|
#define OP_MAX_FULL 10 |
|
|
|
|
|
/* integrity operations */ |
|
|
#define OP_FSYNC 10 |
|
|
#define OP_MAX_INTEGRITY 11 |
|
|
|
|
|
/* operation modifiers */ |
|
|
#define OP_CLOSEOPEN 100 |
|
|
#define OP_SKIPPED 101 |
|
|
@@ -111,6 +117,9 @@ char *original_buf; /* a pointer to the original data */ |
|
|
char *good_buf; /* a pointer to the correct data */ |
|
|
char *temp_buf; /* a pointer to the current data */ |
|
|
char *fname; /* name of our test file */ |
|
|
char *bname; /* basename of our test file */ |
|
|
char *logdev; /* -I flag */ |
|
|
char dname[1024]; /* -P flag */ |
|
|
int fd; /* fd for our test file */ |
|
|
|
|
|
blksize_t block_size = 0; |
|
|
@@ -149,9 +158,11 @@ int zero_range_calls = 1; /* -z flag disables */ |
|
|
int collapse_range_calls = 1; /* -C flag disables */ |
|
|
int insert_range_calls = 1; /* -I flag disables */ |
|
|
int mapped_reads = 1; /* -R flag disables it */ |
|
|
int integrity = 0; /* -I flag */ |
|
|
int fsxgoodfd = 0; |
|
|
int o_direct; /* -Z */ |
|
|
int aio = 0; |
|
|
int mark_nr = 0; |
|
|
|
|
|
int page_size; |
|
|
int page_mask; |
|
|
@@ -350,6 +361,9 @@ logdump(void) |
|
|
lp->args[0] + lp->args[1]) |
|
|
prt("\t******IIII"); |
|
|
break; |
|
|
case OP_FSYNC: |
|
|
prt("FSYNC"); |
|
|
break; |
|
|
case OP_SKIPPED: |
|
|
prt("SKIPPED (no operation)"); |
|
|
break; |
|
|
@@ -428,6 +442,42 @@ report_failure(int status) |
|
|
#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \ |
|
|
*(((unsigned char *)(cp)) + 1))) |
|
|
|
|
|
void |
|
|
mark_log(void) |
|
|
{ |
|
|
char command[256]; |
|
|
int ret; |
|
|
|
|
|
snprintf(command, 256, "dmsetup message %s 0 mark %s.mark%d", logdev, |
|
|
bname, mark_nr); |
|
|
ret = system(command); |
|
|
if (ret) { |
|
|
prterr("dmsetup mark failed"); |
|
|
exit(1); |
|
|
} |
|
|
} |
|
|
|
|
|
void |
|
|
dump_fsync_buffer(void) |
|
|
{ |
|
|
char fname_buffer[1024]; |
|
|
int good_fd; |
|
|
|
|
|
if (!good_buf) |
|
|
return; |
|
|
|
|
|
snprintf(fname_buffer, 1024, "%s%s.mark%d", dname, |
|
|
bname, mark_nr); |
|
|
good_fd = open(fname_buffer, O_WRONLY|O_CREAT|O_TRUNC, 0666); |
|
|
if (good_fd < 0) { |
|
|
prterr(fname_buffer); |
|
|
exit(1); |
|
|
} |
|
|
|
|
|
save_buffer(good_buf, file_size, good_fd); |
|
|
close(good_fd); |
|
|
} |
|
|
|
|
|
void |
|
|
check_buffers(unsigned offset, unsigned size) |
|
|
{ |
|
|
@@ -1183,6 +1233,26 @@ docloseopen(void) |
|
|
} |
|
|
} |
|
|
|
|
|
void |
|
|
dofsync(void) |
|
|
{ |
|
|
int ret; |
|
|
|
|
|
if (testcalls <= simulatedopcount) |
|
|
return; |
|
|
if (debug) |
|
|
prt("%lu fsync\n", testcalls); |
|
|
log4(OP_FSYNC, 0, 0, 0); |
|
|
ret = fsync(fd); |
|
|
if (ret < 0) { |
|
|
prterr("dofsync"); |
|
|
report_failure(190); |
|
|
} |
|
|
mark_log(); |
|
|
dump_fsync_buffer(); |
|
|
printf("Dumped fsync buffer mark %d\n", mark_nr); |
|
|
mark_nr++; |
|
|
} |
|
|
|
|
|
#define TRIM_OFF(off, size) \ |
|
|
do { \ |
|
|
@@ -1233,8 +1303,10 @@ test(void) |
|
|
/* calculate appropriate op to run */ |
|
|
if (lite) |
|
|
op = rv % OP_MAX_LITE; |
|
|
else |
|
|
else if (!integrity) |
|
|
op = rv % OP_MAX_FULL; |
|
|
else |
|
|
op = rv % OP_MAX_INTEGRITY; |
|
|
|
|
|
switch (op) { |
|
|
case OP_MAPREAD: |
|
|
@@ -1343,6 +1415,9 @@ test(void) |
|
|
|
|
|
do_insert_range(offset, size); |
|
|
break; |
|
|
case OP_FSYNC: |
|
|
dofsync(); |
|
|
break; |
|
|
default: |
|
|
prterr("test: unknown operation"); |
|
|
report_failure(42); |
|
|
@@ -1372,7 +1447,7 @@ void |
|
|
usage(void) |
|
|
{ |
|
|
fprintf(stdout, "usage: %s", |
|
|
"fsx [-dnqxAFLOWZ] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\ |
|
|
"fsx [-dnqxAFLOWZ] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] [-I logdev] fname\n\ |
|
|
-b opnum: beginning operation number (default 1)\n\ |
|
|
-c P: 1 in P chance of file close+open at each op (default infinity)\n\ |
|
|
-d: debug output for all operations\n\ |
|
|
@@ -1417,6 +1492,7 @@ usage(void) |
|
|
-W: mapped write operations DISabled\n\ |
|
|
-R: read() system calls only (mapped reads disabled)\n\ |
|
|
-Z: O_DIRECT (use -R, -W, -r and -w too)\n\ |
|
|
-i logdev: do integrity testing, logdev is the dm log writes device\n\ |
|
|
fname: this filename is REQUIRED (no default)\n"); |
|
|
exit(90); |
|
|
} |
|
|
@@ -1580,13 +1656,14 @@ int |
|
|
main(int argc, char **argv) |
|
|
{ |
|
|
int i, style, ch; |
|
|
char *endp; |
|
|
char *endp, *tmp; |
|
|
char goodfile[1024]; |
|
|
char logfile[1024]; |
|
|
struct stat statbuf; |
|
|
|
|
|
goodfile[0] = 0; |
|
|
logfile[0] = 0; |
|
|
dname[0] = 0; |
|
|
|
|
|
page_size = getpagesize(); |
|
|
page_mask = page_size - 1; |
|
|
@@ -1595,7 +1672,7 @@ main(int argc, char **argv) |
|
|
|
|
|
setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */ |
|
|
|
|
|
while ((ch = getopt(argc, argv, "b:c:dfl:m:no:p:qr:s:t:w:xyAD:FKHzCILN:OP:RS:WZ")) |
|
|
while ((ch = getopt(argc, argv, "b:c:dfl:m:no:p:qr:s:t:w:xyAD:FKHzCILN:OP:RS:WZi:")) |
|
|
!= EOF) |
|
|
switch (ch) { |
|
|
case 'b': |
|
|
@@ -1719,10 +1796,11 @@ main(int argc, char **argv) |
|
|
randomoplen = 0; |
|
|
break; |
|
|
case 'P': |
|
|
strncpy(goodfile, optarg, sizeof(goodfile)); |
|
|
strcat(goodfile, "/"); |
|
|
strncpy(logfile, optarg, sizeof(logfile)); |
|
|
strcat(logfile, "/"); |
|
|
strncpy(dname, optarg, sizeof(dname)); |
|
|
strcat(dname, "/"); |
|
|
|
|
|
strncpy(goodfile, dname, sizeof(goodfile)); |
|
|
strncpy(logfile, dname, sizeof(logfile)); |
|
|
break; |
|
|
case 'R': |
|
|
mapped_reads = 0; |
|
|
@@ -1744,6 +1822,14 @@ main(int argc, char **argv) |
|
|
case 'Z': |
|
|
o_direct = O_DIRECT; |
|
|
break; |
|
|
case 'i': |
|
|
integrity = 1; |
|
|
logdev = strdup(optarg); |
|
|
if (!logdev) { |
|
|
prterr("malloc"); |
|
|
exit(1); |
|
|
} |
|
|
break; |
|
|
default: |
|
|
usage(); |
|
|
/* NOTREACHED */ |
|
|
@@ -1753,6 +1839,12 @@ main(int argc, char **argv) |
|
|
if (argc != 1) |
|
|
usage(); |
|
|
fname = argv[0]; |
|
|
tmp = strdup(fname); |
|
|
if (!tmp) { |
|
|
prterr("strdup"); |
|
|
exit(1); |
|
|
} |
|
|
bname = basename(tmp); |
|
|
|
|
|
signal(SIGHUP, cleanup); |
|
|
signal(SIGINT, cleanup); |
|
|
@@ -1795,14 +1887,14 @@ main(int argc, char **argv) |
|
|
} |
|
|
} |
|
|
#endif |
|
|
strncat(goodfile, fname, 256); |
|
|
strncat(goodfile, bname, 256); |
|
|
strcat (goodfile, ".fsxgood"); |
|
|
fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666); |
|
|
if (fsxgoodfd < 0) { |
|
|
prterr(goodfile); |
|
|
exit(92); |
|
|
} |
|
|
strncat(logfile, fname, 256); |
|
|
strncat(logfile, bname, 256); |
|
|
strcat (logfile, ".fsxlog"); |
|
|
fsxlogf = fopen(logfile, "w"); |
|
|
if (fsxlogf == NULL) { |
|
|
@@ -1874,6 +1966,7 @@ main(int argc, char **argv) |
|
|
while (numops == -1 || numops--) |
|
|
test(); |
|
|
|
|
|
free(tmp); |
|
|
if (close(fd)) { |
|
|
prterr("close"); |
|
|
report_failure(99); |
|
|
|