| #include "stdinc.h" |
| #include "dat.h" |
| #include "fns.h" |
| |
| static int verbose; |
| |
| static void |
| checkarena(Arena *arena, int scan, int fix) |
| { |
| ATailStats old; |
| int err, e; |
| |
| if(verbose && arena->memstats.clumps) |
| printarena(2, arena); |
| |
| old = arena->memstats; |
| |
| if(scan){ |
| arena->memstats.used = 0; |
| arena->memstats.clumps = 0; |
| arena->memstats.cclumps = 0; |
| arena->memstats.uncsize = 0; |
| } |
| |
| err = 0; |
| for(;;){ |
| e = syncarena(arena, 1000, 0, fix); |
| err |= e; |
| if(!(e & SyncHeader)) |
| break; |
| if(verbose && arena->memstats.clumps) |
| fprint(2, "."); |
| } |
| if(verbose && arena->memstats.clumps) |
| fprint(2, "\n"); |
| |
| err &= ~SyncHeader; |
| if(arena->memstats.used != old.used |
| || arena->memstats.clumps != old.clumps |
| || arena->memstats.cclumps != old.cclumps |
| || arena->memstats.uncsize != old.uncsize){ |
| fprint(2, "%s: incorrect arena header fields\n", arena->name); |
| printarena(2, arena); |
| err |= SyncHeader; |
| } |
| |
| if(!err || !fix) |
| return; |
| |
| fprint(2, "%s: writing fixed arena header fields\n", arena->name); |
| arena->diskstats = arena->memstats; |
| if(wbarena(arena) < 0) |
| fprint(2, "arena header write failed: %r\n"); |
| flushdcache(); |
| } |
| |
| void |
| usage(void) |
| { |
| fprint(2, "usage: checkarenas [-afv] file [arenaname...]\n"); |
| threadexitsall(0); |
| } |
| |
| int |
| should(char *name, int argc, char **argv) |
| { |
| int i; |
| |
| if(argc == 0) |
| return 1; |
| for(i=0; i<argc; i++) |
| if(strcmp(name, argv[i]) == 0) |
| return 1; |
| return 0; |
| } |
| |
| void |
| threadmain(int argc, char *argv[]) |
| { |
| ArenaPart *ap; |
| Part *part; |
| char *file; |
| int i, fix, scan; |
| |
| ventifmtinstall(); |
| statsinit(); |
| |
| fix = 0; |
| scan = 0; |
| ARGBEGIN{ |
| case 'f': |
| fix++; |
| break; |
| case 'a': |
| scan = 1; |
| break; |
| case 'v': |
| verbose++; |
| break; |
| default: |
| usage(); |
| break; |
| }ARGEND |
| |
| if(!fix) |
| readonly = 1; |
| |
| if(argc < 1) |
| usage(); |
| |
| file = argv[0]; |
| argc--; |
| argv++; |
| |
| part = initpart(file, (fix ? ORDWR : OREAD)|ODIRECT); |
| if(part == nil) |
| sysfatal("can't open partition %s: %r", file); |
| |
| ap = initarenapart(part); |
| if(ap == nil) |
| sysfatal("can't initialize arena partition in %s: %r", file); |
| |
| if(verbose > 1){ |
| printarenapart(2, ap); |
| fprint(2, "\n"); |
| } |
| |
| initdcache(8 * MaxDiskBlock); |
| |
| for(i = 0; i < ap->narenas; i++) |
| if(should(ap->arenas[i]->name, argc, argv)) { |
| debugarena = i; |
| checkarena(ap->arenas[i], scan, fix); |
| } |
| |
| if(verbose > 1) |
| printstats(); |
| threadexitsall(0); |
| } |