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:
Andriy Gapon 2013-11-19 18:35:38 +00:00
parent 2f0f2d0f38
commit d9b7800b54

View File

@ -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;
}
opnum = i + 1 + (logcount/LOGSIZE)*LOGSIZE;
for ( ; count > 0; count--) {
int opnum;
opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
prt("%d(%d mod 256): ", opnum, opnum%256);
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)