From d9b7800b54a044613d8f8c86dc5e7e49c88787f9 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Tue, 19 Nov 2013 18:35:38 +0000 Subject: [PATCH] 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 --- tools/regression/fsx/fsx.c | 96 ++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 14 deletions(-) diff --git a/tools/regression/fsx/fsx.c b/tools/regression/fsx/fsx.c index 7f25d33aaed8..5e9b45178c93 100644 --- a/tools/regression/fsx/fsx.c +++ b/tools/regression/fsx/fsx.c @@ -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)