Index: main.c =================================================================== RCS file: /cvsroot/squid/squid/src/main.c,v retrieving revision 1.2 diff -u -r1.2 main.c --- main.c 2000/10/21 15:16:12 1.2 +++ main.c 2000/10/30 11:58:26 @@ -101,7 +101,8 @@ " -F Don't serve any requests until store is rebuilt.\n" " -N No daemon mode.\n" " -R Do not set REUSEADDR on port.\n" - " -S Double-check swap during rebuild.\n" + " -S force Force double-check swap during rebuild.\n" + " -S reportonly Force double-check but do not attempt repair.\n" " -V Virtual host httpd-accelerator.\n" " -X Force full debugging.\n" " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n", @@ -115,7 +116,7 @@ extern char *optarg; int c; - while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) { + while ((c = getopt(argc, argv, "CDFNRS:VYXa:d:f:hk:m::su:vz?")) != -1) { switch (c) { case 'C': opt_catch_signals = 0; @@ -133,7 +134,14 @@ opt_reuseaddr = 0; break; case 'S': - opt_store_doublecheck = 1; + if ((int) strlen(optarg) < 1) + usage(); + else if (!strncmp(optarg, "force", strlen(optarg))) + opt_store_doublecheck = 1; /* trigger a doublecheck on startup */ + else if (!strncmp(optarg, "reportonly", strlen(optarg))) + opt_store_doublecheck = 2; /* trigger a doublecheck that doesn't repair */ + else + usage(); break; case 'V': vhost_mode = 1; Index: store_rebuild.c =================================================================== RCS file: /cvsroot/squid/squid/src/store_rebuild.c,v retrieving revision 1.2 diff -u -r1.2 store_rebuild.c --- store_rebuild.c 2000/10/21 15:16:13 1.2 +++ store_rebuild.c 2000/10/30 11:58:26 @@ -65,6 +65,7 @@ store_dirs_rebuilding--; assert(0 == store_dirs_rebuilding); if (opt_store_doublecheck) + /* we want to assert here because the storeFScode should auto-clean the entries */ assert(store_errors == 0); if (store_digest) storeDigestNoteStoreReady(); @@ -83,8 +84,10 @@ if (e->swap_filen < 0) continue; if (opt_store_doublecheck) - if (storeCleanupDoubleCheck(e)) + if (storeCleanupDoubleCheck(e)){ + /* this should never happen as the storeFScode should auto-clean */ store_errors++; + } EBIT_SET(e->flags, ENTRY_VALIDATED); /* * Only set the file bit if we know its a valid entry @@ -112,6 +115,8 @@ counts.invalid += dc->invalid; counts.badflags += dc->badflags; counts.bad_log_op += dc->bad_log_op; + counts.missingcount += dc->missingcount; + counts.filesizemismatchcount += dc->filesizemismatchcount; counts.zero_object_sz += dc->zero_object_sz; /* * When store_dirs_rebuilding == 1, it means we are done reading @@ -130,6 +135,8 @@ debug(20, 1) (" %7d Objects cancelled.\n", counts.cancelcount); debug(20, 1) (" %7d Duplicate URLs purged.\n", counts.dupcount); debug(20, 1) (" %7d Swapfile clashes avoided.\n", counts.clashcount); + debug(20, 1) (" %7d Missing files ignored.\n", counts.missingcount); + debug(20, 1) (" %7d Incorrect length swapfiles %s.\n", counts.filesizemismatchcount, (opt_store_doublecheck==2) ? "ignored" : "unlinked"); debug(20, 1) (" Took %3.1f seconds (%6.1f objects/sec).\n", dt, (double) counts.objcount / (dt > 0.0 ? dt : 1.0)); debug(20, 1) ("Beginning Validation Procedure\n"); Index: structs.h =================================================================== RCS file: /cvsroot/squid/squid/src/structs.h,v retrieving revision 1.2 diff -u -r1.2 structs.h --- structs.h 2000/10/21 15:16:13 1.2 +++ structs.h 2000/10/30 11:58:33 @@ -1841,6 +1841,8 @@ int cancelcount; /* # SWAP_LOG_DEL objects purged */ int invalid; /* # bad lines */ int badflags; /* # bad e->flags */ + int missingcount; /* # swapfiles not on disk */ + int filesizemismatchcount; /* # swapfiles with a wrong size */ int bad_log_op; int zero_object_sz; }; Index: fs/aufs/store_dir_aufs.c =================================================================== RCS file: /cvsroot/squid/squid/src/fs/aufs/store_dir_aufs.c,v retrieving revision 1.2 diff -u -r1.2 store_dir_aufs.c --- fs/aufs/store_dir_aufs.c 2000/10/21 16:44:45 1.2 +++ fs/aufs/store_dir_aufs.c 2000/10/30 11:58:45 @@ -119,6 +119,7 @@ static int storeAufsDirIs(SwapDir * sd); static int storeAufsFilenoBelongsHere(int fn, int F0, int F1, int F2); static int storeAufsCleanupDoubleCheck(SwapDir *, StoreEntry *); +static int storeAufsCheckFile(SwapDir * sd, sfileno filn, size_t swap_file_sz ); static void storeAufsDirStats(SwapDir *, StoreEntry *); static void storeAufsDirInitBitmap(SwapDir *); static int storeAufsDirValidFileno(SwapDir *, sfileno, int); @@ -477,6 +478,7 @@ debug(20, 1) ("storeAufsDirRebuildFromDirectory: SIZE MISMATCH %d!=%d\n", tmpe.swap_file_sz, (int) sb.st_size); storeAufsDirUnlinkFile(SD, sfileno); + rb->counts.filesizemismatchcount++; continue; } if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) { @@ -524,6 +526,7 @@ int count; int used; /* is swapfile already in use? */ int disk_entry_newer; /* is the log entry newer than current entry? */ + int file_bad; double x; assert(rb != NULL); /* load a number of objects per invocation */ @@ -606,7 +609,20 @@ * appear to have a newer entry? Compare 'lastref' from the * swap log to e->lastref. */ disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0; - if (used && !disk_entry_newer) { + if (!used && (rb->flags.need_to_validate || opt_store_doublecheck)){ + file_bad = storeAufsCheckFile(SD, s.swap_filen, s.swap_file_sz); + } else + file_bad = 0; + if (file_bad){ + if (file_bad==-2){ + if (opt_store_doublecheck != 2) + storeAufsDirUnlinkFile(SD, s.swap_filen); + rb->counts.filesizemismatchcount++; + continue; + } + rb->counts.missingcount++; + continue; + } else if (used && !disk_entry_newer) { /* log entry is old, ignore it */ rb->counts.clashcount++; continue; @@ -1591,25 +1607,34 @@ static int storeAufsCleanupDoubleCheck(SwapDir * sd, StoreEntry * e) { + int rv= storeAufsCheckFile(sd, e->swap_filen, e->swap_file_sz); + if (rv) storeEntryDump(e, 0); + return rv; +} + +/* + * storeAufsCheckFile + * + * This is called by storerebuildFromSwapLog if -S was given on the command + * line. or a Dirty state is found + */ +static int +storeAufsCheckFile(SwapDir * sd, sfileno filen, size_t swap_file_sz ) +{ struct stat sb; - if (stat(storeAufsDirFullPath(sd, e->swap_filen, NULL), &sb) < 0) { - debug(20, 0) ("storeAufsCleanupDoubleCheck: MISSING SWAP FILE\n"); - debug(20, 0) ("storeAufsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); - debug(20, 0) ("storeAufsCleanupDoubleCheck: PATH %s\n", - storeAufsDirFullPath(sd, e->swap_filen, NULL)); - storeEntryDump(e, 0); - return -1; - } - if (e->swap_file_sz != sb.st_size) { - debug(20, 0) ("storeAufsCleanupDoubleCheck: SIZE MISMATCH\n"); - debug(20, 0) ("storeAufsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); - debug(20, 0) ("storeAufsCleanupDoubleCheck: PATH %s\n", - storeAufsDirFullPath(sd, e->swap_filen, NULL)); - debug(20, 0) ("storeAufsCleanupDoubleCheck: ENTRY SIZE: %d, FILE SIZE: %d\n", - e->swap_file_sz, (int) sb.st_size); - storeEntryDump(e, 0); - return -1; + if (stat(storeAufsDirFullPath(sd, filen, NULL), &sb) < 0) { + debug(20, 1) ("storeAufsCheckFile: MISSING SWAP FILE\n"); + debug(20, 1) ("storeAufsCheckFile: FILENO %08X\n", filen); + debug(20, 1) ("storeAufsCheckFile: PATH %s\n", storeAufsDirFullPath(sd, filen, NULL)); + return -1; + } + if (swap_file_sz != sb.st_size) { + debug(20, 1) ("storeAufsCheckFile: SIZE MISMATCH\n"); + debug(20, 1) ("storeAufsCheckFile: FILENO %08X\n", filen); + debug(20, 1) ("storeAufsCheckFile: PATH %s\n", storeAufsDirFullPath(sd, filen, NULL)); + debug(20, 1) ("storeAufsCheckFile: ENTRY SIZE: %d, FILE SIZE: %d\n", swap_file_sz, (int) sb.st_size); + return -2; } return 0; } Index: fs/diskd/store_dir_diskd.c =================================================================== RCS file: /cvsroot/squid/squid/src/fs/diskd/store_dir_diskd.c,v retrieving revision 1.2 diff -u -r1.2 store_dir_diskd.c --- fs/diskd/store_dir_diskd.c 2000/10/21 16:44:45 1.2 +++ fs/diskd/store_dir_diskd.c 2000/10/30 11:58:49 @@ -127,6 +127,7 @@ static int storeDiskdDirIs(SwapDir * sd); static int storeDiskdFilenoBelongsHere(int fn, int F0, int F1, int F2); static int storeDiskdCleanupDoubleCheck(SwapDir *, StoreEntry *); +static int storeDiskdCheckFile(SwapDir * sd, sfileno filn, size_t swap_file_sz); static void storeDiskdDirStats(SwapDir *, StoreEntry *); static void storeDiskdDirInitBitmap(SwapDir *); static int storeDiskdDirValidFileno(SwapDir *, sfileno, int); @@ -643,6 +644,7 @@ debug(20, 1) ("storeDiskdDirRebuildFromDirectory: SIZE MISMATCH %d!=%d\n", tmpe.swap_file_sz, (int) sb.st_size); storeDiskdDirUnlinkFile(SD, sfileno); + rb->counts.filesizemismatchcount++; continue; } if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) { @@ -690,6 +692,7 @@ int count; int used; /* is swapfile already in use? */ int disk_entry_newer; /* is the log entry newer than current entry? */ + int file_bad; double x; assert(rb != NULL); /* load a number of objects per invocation */ @@ -797,7 +800,20 @@ * appear to have a newer entry? Compare 'lastref' from the * swap log to e->lastref. */ disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0; - if (used && !disk_entry_newer) { + if (!used && (rb->flags.need_to_validate || opt_store_doublecheck)){ + file_bad = storeDiskdCheckFile(SD, s.swap_filen, s.swap_file_sz); + } else + file_bad = 0; + if (file_bad){ + if (file_bad==-2){ + if (opt_store_doublecheck != 2) + storeDiskdDirUnlinkFile(SD, s.swap_filen); + rb->counts.filesizemismatchcount++; + continue; + } + rb->counts.missingcount++; + continue; + } else if (used && !disk_entry_newer) { /* log entry is old, ignore it */ rb->counts.clashcount++; continue; @@ -1825,26 +1841,35 @@ static int storeDiskdCleanupDoubleCheck(SwapDir * sd, StoreEntry * e) { - struct stat sb; + int rv= storeDiskdCheckFile(sd, e->swap_filen, e->swap_file_sz); + if (rv) storeEntryDump(e, 0); + return rv; +} - if (stat(storeDiskdDirFullPath(sd, e->swap_filen, NULL), &sb) < 0) { - debug(20, 0) ("storeDiskdCleanupDoubleCheck: MISSING SWAP FILE\n"); - debug(20, 0) ("storeDiskdCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); - debug(20, 0) ("storeDiskdCleanupDoubleCheck: PATH %s\n", - storeDiskdDirFullPath(sd, e->swap_filen, NULL)); - storeEntryDump(e, 0); - return -1; - } - if (e->swap_file_sz != sb.st_size) { - debug(20, 0) ("storeDiskdCleanupDoubleCheck: SIZE MISMATCH\n"); - debug(20, 0) ("storeDiskdCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); - debug(20, 0) ("storeDiskdCleanupDoubleCheck: PATH %s\n", - storeDiskdDirFullPath(sd, e->swap_filen, NULL)); - debug(20, 0) ("storeDiskdCleanupDoubleCheck: ENTRY SIZE: %d, FILE SIZE: %d\n", - e->swap_file_sz, (int) sb.st_size); - storeEntryDump(e, 0); - return -1; - } +/* + * storeDiskdCheckFile + * + * This is called by storerebuildFromSwapLog if -S was given on the command line * or a Dirty state is found + */ +static int +storeDiskdCheckFile(SwapDir * sd, sfileno filen, size_t swap_file_sz ) +{ + struct stat sb; + + if (stat(storeDiskdDirFullPath(sd, filen, NULL), &sb) < 0) { + debug(20, 1) ("storeDiskdCheckFile: MISSING SWAP FILE\n"); + debug(20, 1) ("storeDiskdCheckFile: FILENO %08X\n", filen); + debug(20, 1) ("storeDiskdCheckFile: PATH %s\n", storeDiskdDirFullPath(sd, filen, NULL)); + + return -1; + } + if (swap_file_sz != sb.st_size) { + debug(20, 1) ("storeDiskdCheckFile: SIZE MISMATCH\n"); + debug(20, 1) ("storeDiskdCheckFile: FILENO %08X\n", filen); + debug(20, 1) ("storeDiskdCheckFile: PATH %s\n", storeDiskdDirFullPath(sd, filen, NULL)); + debug(20, 1) ("storeDiskdCheckFile: ENTRY SIZE: %d, FILE SIZE: %d\n", swap_file_sz, (int) sb.st_size); + return -2; + } return 0; } Index: fs/ufs/store_dir_ufs.c =================================================================== RCS file: /cvsroot/squid/squid/src/fs/ufs/store_dir_ufs.c,v retrieving revision 1.2 diff -u -r1.2 store_dir_ufs.c --- fs/ufs/store_dir_ufs.c 2000/10/21 16:44:46 1.2 +++ fs/ufs/store_dir_ufs.c 2000/10/30 11:58:54 @@ -117,6 +117,7 @@ static int storeUfsDirIs(SwapDir * sd); static int storeUfsFilenoBelongsHere(int fn, int F0, int F1, int F2); static int storeUfsCleanupDoubleCheck(SwapDir *, StoreEntry *); +static int storeUfsCheckFile(SwapDir * sd, sfileno filn, size_t swap_file_sz ); static void storeUfsDirStats(SwapDir *, StoreEntry *); static void storeUfsDirInitBitmap(SwapDir *); static int storeUfsDirValidFileno(SwapDir *, sfileno, int); @@ -475,6 +476,7 @@ debug(20, 1) ("storeUfsDirRebuildFromDirectory: SIZE MISMATCH %d!=%d\n", tmpe.swap_file_sz, (int) sb.st_size); storeUfsDirUnlinkFile(SD, sfileno); + rb->counts.filesizemismatchcount++; continue; } if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) { @@ -522,6 +524,7 @@ int count; int used; /* is swapfile already in use? */ int disk_entry_newer; /* is the log entry newer than current entry? */ + int file_bad; double x; assert(rb != NULL); /* load a number of objects per invocation */ @@ -604,7 +607,20 @@ * appear to have a newer entry? Compare 'lastref' from the * swap log to e->lastref. */ disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0; - if (used && !disk_entry_newer) { + if (!used && (rb->flags.need_to_validate || opt_store_doublecheck)){ + file_bad = storeUfsCheckFile(SD, s.swap_filen, s.swap_file_sz); + } else + file_bad = 0; + if (file_bad){ + if (file_bad==-2){ + if (opt_store_doublecheck != 2) + storeUfsDirUnlinkFile(SD, s.swap_filen); + rb->counts.filesizemismatchcount++; + continue; + } + rb->counts.missingcount++; + continue; + }else if (used && !disk_entry_newer) { /* log entry is old, ignore it */ rb->counts.clashcount++; continue; @@ -667,19 +683,19 @@ /* load new */ (void) 0; } - /* update store_swap_size */ - rb->counts.objcount++; - e = storeUfsDirAddDiskRestore(SD, s.key, - s.swap_filen, - s.swap_file_sz, - s.expires, - s.timestamp, - s.lastref, - s.lastmod, - s.refcount, - s.flags, - (int) rb->flags.clean); - storeDirSwapLog(e, SWAP_LOG_ADD); + /* update store_swap_size */ + rb->counts.objcount++; + e = storeUfsDirAddDiskRestore(SD, s.key, + s.swap_filen, + s.swap_file_sz, + s.expires, + s.timestamp, + s.lastref, + s.lastmod, + s.refcount, + s.flags, + (int) rb->flags.clean); + storeDirSwapLog(e, SWAP_LOG_ADD); } eventAdd("storeRebuild", storeUfsDirRebuildFromSwapLog, rb, 0.0, 1); } @@ -1577,28 +1593,39 @@ static int storeUfsCleanupDoubleCheck(SwapDir * sd, StoreEntry * e) { + int rv= storeUfsCheckFile(sd, e->swap_filen, e->swap_file_sz); + if (rv) storeEntryDump(e, 0); + return rv; +} + +/* + * storeUfsCheckFile + * + * This is called by storerebuildFromSwapLog if -S was given on the command line. or a Dirty state is found + */ +static int +storeUfsCheckFile(SwapDir * sd, sfileno filen, size_t swap_file_sz ) +{ struct stat sb; - if (stat(storeUfsDirFullPath(sd, e->swap_filen, NULL), &sb) < 0) { - debug(20, 0) ("storeUfsCleanupDoubleCheck: MISSING SWAP FILE\n"); - debug(20, 0) ("storeUfsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); - debug(20, 0) ("storeUfsCleanupDoubleCheck: PATH %s\n", - storeUfsDirFullPath(sd, e->swap_filen, NULL)); - storeEntryDump(e, 0); - return -1; + if (stat(storeUfsDirFullPath(sd, filen, NULL), &sb) < 0) { + debug(20, 1) ("storeUfsCheckFile: MISSING SWAP FILE\n"); + debug(20, 1) ("storeUfsCheckFile: FILENO %08X\n", filen); + debug(20, 1) ("storeUfsCheckFile: PATH %s\n", storeUfsDirFullPath(sd, filen, NULL)); + + return -1; + } + if (swap_file_sz != sb.st_size) { + debug(20, 1) ("storeUfsCheckFile: SIZE MISMATCH\n"); + debug(20, 1) ("storeUfsCheckFile: FILENO %08X\n", filen); + debug(20, 1) ("storeUfsCheckFile: PATH %s\n", storeUfsDirFullPath(sd, filen, NULL)); + debug(20, 1) ("storeUfsCheckFile: ENTRY SIZE: %d, FILE SIZE: %d\n", swap_file_sz, (int) sb.st_size); + return -2; } - if (e->swap_file_sz != sb.st_size) { - debug(20, 0) ("storeUfsCleanupDoubleCheck: SIZE MISMATCH\n"); - debug(20, 0) ("storeUfsCleanupDoubleCheck: FILENO %08X\n", e->swap_filen); - debug(20, 0) ("storeUfsCleanupDoubleCheck: PATH %s\n", - storeUfsDirFullPath(sd, e->swap_filen, NULL)); - debug(20, 0) ("storeUfsCleanupDoubleCheck: ENTRY SIZE: %d, FILE SIZE: %d\n", - e->swap_file_sz, (int) sb.st_size); - storeEntryDump(e, 0); - return -1; - } return 0; } + + /* * storeUfsDirParse