fsx: add an option to randomly call msync(MS_INVALIDATE)
This call should be a sufficiently close approximation of what happens when a filesystem is unmounted and remounted. To be more specific, it should test that the data that was in the page cache is the same data that ends up on a stable storage or in a filesystem's internal cache, if any. This will catch the cases where a page with modified data is marked as a clean page for whatever reason. While there, make logging of the special events (open+close before plus invalidation now) more generic and slightly better than the previous hack. MFC after: 10 days
This commit is contained in:
parent
2f0f2d0f38
commit
d9b7800b54
@ -90,6 +90,7 @@ int logcount = 0; /* total ops */
|
||||
#define OP_MAPREAD 5
|
||||
#define OP_MAPWRITE 6
|
||||
#define OP_SKIPPED 7
|
||||
#define OP_INVALIDATE 8
|
||||
|
||||
int page_size;
|
||||
int page_mask;
|
||||
@ -107,6 +108,7 @@ unsigned long testcalls = 0; /* calls to function "test" */
|
||||
|
||||
unsigned long simulatedopcount = 0; /* -b flag */
|
||||
int closeprob = 0; /* -c flag */
|
||||
int invlprob = 0; /* -i flag */
|
||||
int debug = 0; /* -d flag */
|
||||
unsigned long debugstart = 0; /* -D flag */
|
||||
unsigned long maxfilelen = 256 * 1024; /* -l flag */
|
||||
@ -131,6 +133,7 @@ int fsxgoodfd = 0;
|
||||
FILE * fsxlogf = NULL;
|
||||
int badoff = -1;
|
||||
int closeopen = 0;
|
||||
int invl = 0;
|
||||
|
||||
|
||||
void
|
||||
@ -182,14 +185,12 @@ prterr(char *prefix)
|
||||
|
||||
|
||||
void
|
||||
log4(int operation, int arg0, int arg1, int arg2)
|
||||
do_log4(int operation, int arg0, int arg1, int arg2)
|
||||
{
|
||||
struct log_entry *le;
|
||||
|
||||
le = &oplog[logptr];
|
||||
le->operation = operation;
|
||||
if (closeopen)
|
||||
le->operation = ~ le->operation;
|
||||
le->args[0] = arg0;
|
||||
le->args[1] = arg1;
|
||||
le->args[2] = arg2;
|
||||
@ -200,11 +201,22 @@ log4(int operation, int arg0, int arg1, int arg2)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
log4(int operation, int arg0, int arg1, int arg2)
|
||||
{
|
||||
do_log4(operation, arg0, arg1, arg2);
|
||||
if (closeopen)
|
||||
do_log4(OP_CLOSEOPEN, 0, 0, 0);
|
||||
if (invl)
|
||||
do_log4(OP_INVALIDATE, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
logdump(void)
|
||||
{
|
||||
int i, count, down;
|
||||
struct log_entry *lp;
|
||||
int i, count, down, opnum;
|
||||
|
||||
prt("LOG DUMP (%d total operations):\n", logcount);
|
||||
if (logcount < LOGSIZE) {
|
||||
@ -214,15 +226,28 @@ logdump(void)
|
||||
i = logptr;
|
||||
count = LOGSIZE;
|
||||
}
|
||||
for ( ; count > 0; count--) {
|
||||
int opnum;
|
||||
|
||||
opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
|
||||
prt("%d(%d mod 256): ", opnum, opnum%256);
|
||||
opnum = i + 1 + (logcount/LOGSIZE)*LOGSIZE;
|
||||
for ( ; count > 0; count--) {
|
||||
lp = &oplog[i];
|
||||
if ((closeopen = lp->operation < 0))
|
||||
lp->operation = ~ lp->operation;
|
||||
|
||||
|
||||
if (lp->operation == OP_CLOSEOPEN ||
|
||||
lp->operation == OP_INVALIDATE) {
|
||||
switch (lp->operation) {
|
||||
case OP_CLOSEOPEN:
|
||||
prt("\t\tCLOSE/OPEN\n");
|
||||
break;
|
||||
case OP_INVALIDATE:
|
||||
prt("\t\tMS_INVALIDATE\n");
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
if (i == LOGSIZE)
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
prt("%d(%d mod 256): ", opnum, opnum%256);
|
||||
switch (lp->operation) {
|
||||
case OP_MAPREAD:
|
||||
prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)",
|
||||
@ -275,9 +300,8 @@ logdump(void)
|
||||
prt("BOGUS LOG ENTRY (operation code = %d)!",
|
||||
lp->operation);
|
||||
}
|
||||
if (closeopen)
|
||||
prt("\n\t\tCLOSE/OPEN");
|
||||
prt("\n");
|
||||
opnum++;
|
||||
i++;
|
||||
if (i == LOGSIZE)
|
||||
i = 0;
|
||||
@ -778,6 +802,36 @@ docloseopen(void)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
doinvl(void)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (file_size == 0)
|
||||
return;
|
||||
if (testcalls <= simulatedopcount)
|
||||
return;
|
||||
if (debug)
|
||||
prt("%lu msync(MS_INVALIDATE)\n", testcalls);
|
||||
|
||||
if ((p = (char *)mmap(0, file_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FILE | MAP_SHARED, fd, 0)) == MAP_FAILED) {
|
||||
prterr("doinvl: mmap");
|
||||
report_failure(205);
|
||||
}
|
||||
|
||||
if (msync(p, 0, MS_SYNC | MS_INVALIDATE) != 0) {
|
||||
prterr("doinvl: msync");
|
||||
report_failure(206);
|
||||
}
|
||||
|
||||
if (munmap(p, file_size) != 0) {
|
||||
prterr("doinvl: munmap");
|
||||
report_failure(207);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
test(void)
|
||||
{
|
||||
@ -798,6 +852,8 @@ test(void)
|
||||
|
||||
if (closeprob)
|
||||
closeopen = (rv >> 3) < (1 << 28) / closeprob;
|
||||
if (invlprob)
|
||||
invl = (rv >> 3) < (1 << 28) / invlprob;
|
||||
|
||||
if (debugstart > 0 && testcalls >= debugstart)
|
||||
debug = 1;
|
||||
@ -845,6 +901,8 @@ test(void)
|
||||
}
|
||||
if (sizechecks && testcalls > simulatedopcount)
|
||||
check_size();
|
||||
if (invl)
|
||||
doinvl();
|
||||
if (closeopen)
|
||||
docloseopen();
|
||||
}
|
||||
@ -869,6 +927,7 @@ usage(void)
|
||||
-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\
|
||||
-i P: 1 in P chance of calling msync(MS_INVALIDATE) (default infinity)\n\
|
||||
-l flen: the upper bound on file size (default 262144)\n\
|
||||
-m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
|
||||
-n: no verifications of file size\n\
|
||||
@ -944,7 +1003,7 @@ main(int argc, char **argv)
|
||||
setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
|
||||
|
||||
while ((ch = getopt(argc, argv,
|
||||
"b:c:dl:m:no:p:qr:s:t:w:D:LN:OP:RS:UW")) != -1)
|
||||
"b:c:di:l:m:no:p:qr:s:t:w:D:LN:OP:RS:UW")) != -1)
|
||||
switch (ch) {
|
||||
case 'b':
|
||||
simulatedopcount = getnum(optarg, &endp);
|
||||
@ -967,6 +1026,15 @@ main(int argc, char **argv)
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'i':
|
||||
invlprob = getnum(optarg, &endp);
|
||||
if (!quiet)
|
||||
fprintf(stdout,
|
||||
"Chance of MS_INVALIDATE is 1 in %d\n",
|
||||
invlprob);
|
||||
if (invlprob <= 0)
|
||||
usage();
|
||||
break;
|
||||
case 'l':
|
||||
maxfilelen = getnum(optarg, &endp);
|
||||
if (maxfilelen <= 0)
|
||||
|
Loading…
Reference in New Issue
Block a user