1 #include "all.h" 2 extern void *malloc(ulong); 3 4 #define DSIZE 546000 5 #define MAXDEPTH 100 6 7 static char* abits; 8 static long sizabits; 9 static char* qbits; 10 static long sizqbits; 11 static char* name; 12 static long sizname; 13 static long fstart; 14 static long fsize; 15 static long nfiles; 16 static long maxq; 17 static char* calloc; 18 static char* callocbase; 19 static Device dev; 20 static long ndup; 21 static long nused; 22 static long nfdup; 23 static long nqbad; 24 static long nfree; 25 static long nbad; 26 static int mod; 27 static int flags; 28 static int ronly; 29 static int cwflag; 30 static long sbaddr; 31 static long oldblock; 32 static int depth; 33 static int maxdepth; 34 35 /* local prototypes */ 36 static int fsck(Dentry*); 37 static void ckfreelist(Superb*); 38 static void mkfreelist(Superb*); 39 static Dentry* maked(long, int, long); 40 static void modd(long, int, Dentry*); 41 static void xread(long, long); 42 static int amark(long); 43 static int fmark(long); 44 static void missing(void); 45 static void qmark(long); 46 static void* zalloc(ulong); 47 static void* dalloc(ulong); 48 static Iobuf* xtag(long, int, long); 49 50 static 51 void* 52 zalloc(ulong n) 53 { 54 char *p; 55 56 p = malloc(n); 57 if(p == 0) 58 panic("zalloc: out of memory\n"); 59 memset(p, '\0', n); 60 return p; 61 } 62 63 static 64 void* 65 dalloc(ulong n) 66 { 67 char *p; 68 69 if(callocbase == 0) 70 calloc = callocbase = zalloc(MAXDEPTH*sizeof(Dentry)); 71 p = calloc; 72 calloc += n; 73 if(calloc > callocbase+MAXDEPTH*sizeof(Dentry)) 74 panic("dalloc too much memory\n"); 75 return p; 76 } 77 78 void 79 check(Filsys *fs, long flag) 80 { 81 Iobuf *p; 82 Superb *sb; 83 Dentry *d; 84 long raddr; 85 86 wlock(&mainlock); 87 dev = fs->dev; 88 flags = flag; 89 calloc = callocbase; 90 91 sizqbits = ((1<<16) + 7) / 8; /* botch */ 92 qbits = zalloc(sizqbits); 93 94 sizname = 4000; 95 name = zalloc(sizname); 96 sizname -= NAMELEN+10; /* for safety */ 97 98 sbaddr = superaddr(dev); 99 raddr = getraddr(dev); 100 p = xtag(sbaddr, Tsuper, QPSUPER); 101 if(!p){ 102 cprint("bad superblock\n"); 103 goto out; 104 } 105 sb = (Superb*)p->iobuf; 106 fstart = 1; 107 108 fsize = sb->fsize; 109 sizabits = (fsize-fstart + 7)/8; 110 abits = zalloc(sizabits); 111 112 mod = 0; 113 nfree = 0; 114 nfdup = 0; 115 nused = 0; 116 nbad = 0; 117 ndup = 0; 118 nqbad = 0; 119 depth = 0; 120 maxdepth = 0; 121 122 if(flags & Ctouch) { 123 oldblock = fsize/DSIZE; 124 oldblock *= DSIZE; 125 if(oldblock < 0) 126 oldblock = 0; 127 cprint("oldblock = %ld\n", oldblock); 128 } 129 if(amark(sbaddr)) 130 ; 131 if(cwflag) { 132 if(amark(sb->roraddr)) 133 ; 134 if(amark(sb->next)) 135 ; 136 } 137 138 if(!(flags & Cquiet)) 139 cprint("checking file system: %s\n", fs->name); 140 nfiles = 0; 141 maxq = 0; 142 143 d = maked(raddr, 0, QPROOT); 144 if(d) { 145 if(amark(raddr)) 146 ; 147 if(fsck(d)) 148 modd(raddr, 0, d); 149 depth--; 150 calloc -= sizeof(Dentry); 151 if(depth) 152 cprint("depth not zero on return\n"); 153 } 154 155 if(flags & Cfree) { 156 mkfreelist(sb); 157 sb->qidgen = maxq; 158 settag(p, Tsuper, QPNONE); 159 } 160 161 if(sb->qidgen < maxq) 162 cprint("qid generator low path=%ld maxq=%ld\n", 163 sb->qidgen, maxq); 164 if(!(flags & Cfree)) 165 ckfreelist(sb); 166 if(mod) { 167 cprint("file system was modified\n"); 168 settag(p, Tsuper, QPNONE); 169 } 170 171 if(!(flags & Cquiet)){ 172 cprint("%8ld files\n", nfiles); 173 cprint("%8ld blocks in the file system\n", fsize-fstart); 174 cprint("%8ld used blocks\n", nused); 175 cprint("%8ld free blocks\n", sb->tfree); 176 } 177 if(!(flags & Cfree)){ 178 if(nfree != sb->tfree) 179 cprint("%8ld free blocks found\n", nfree); 180 if(nfdup) 181 cprint("%8ld blocks duplicated in the free list\n", nfdup); 182 if(fsize-fstart-nused-nfree) 183 cprint("%8ld missing blocks\n", fsize-fstart-nused-nfree); 184 } 185 if(ndup) 186 cprint("%8ld address duplications\n", ndup); 187 if(nbad) 188 cprint("%8ld bad block addresses\n", nbad); 189 if(nqbad) 190 cprint("%8ld bad qids\n", nqbad); 191 if(!(flags & Cquiet)) 192 cprint("%8ld maximum qid path\n", maxq); 193 missing(); 194 195 out: 196 if(p) 197 putbuf(p); 198 free(abits); 199 free(name); 200 free(qbits); 201 wunlock(&mainlock); 202 } 203 204 static 205 int 206 touch(long a) 207 { 208 Iobuf *p; 209 210 if((flags&Ctouch) && a && a < oldblock){ 211 p = getbuf(dev, a, Bread|Bmod); 212 if(p) 213 putbuf(p); 214 return 1; 215 } 216 return 0; 217 } 218 219 static 220 int 221 checkdir(long a, long qpath) 222 { 223 Dentry *nd; 224 int i, ns, dmod; 225 226 ns = strlen(name); 227 dmod = touch(a); 228 for(i=0; i<DIRPERBUF; i++) { 229 nd = maked(a, i, qpath); 230 if(!nd) 231 break; 232 if(fsck(nd)) { 233 modd(a, i, nd); 234 dmod++; 235 } 236 depth--; 237 calloc -= sizeof(Dentry); 238 name[ns] = 0; 239 } 240 name[ns] = 0; 241 return dmod; 242 } 243 244 static 245 int 246 checkindir(long a, Dentry *d, long qpath) 247 { 248 Iobuf *p; 249 int i, dmod; 250 251 dmod = touch(a); 252 p = xtag(a, Tind1, qpath); 253 if(!p) 254 return dmod; 255 for(i=0; i<INDPERBUF; i++) { 256 a = ((long*)p->iobuf)[i]; 257 if(!a) 258 continue; 259 if(amark(a)) { 260 if(flags & Cbad) { 261 ((long*)p->iobuf)[i] = 0; 262 p->flags |= Bmod; 263 } 264 continue; 265 } 266 if(d->mode & DDIR) 267 dmod += checkdir(a, qpath); 268 else if(flags & Crdall) 269 xread(a, qpath); 270 } 271 putbuf(p); 272 return dmod; 273 } 274 275 static 276 int 277 fsck(Dentry *d) 278 { 279 Iobuf *p; 280 int i, ns, dmod; 281 long a, qpath; 282 283 depth++; 284 if(depth >= maxdepth){ 285 maxdepth = depth; 286 if(maxdepth >= MAXDEPTH){ 287 cprint("max depth exceeded: %s\n", name); 288 return 0; 289 } 290 } 291 dmod = 0; 292 if(!(d->mode & DALLOC)) 293 return 0; 294 nfiles++; 295 296 ns = strlen(name); 297 i = strlen(d->name); 298 if(i >= NAMELEN){ 299 d->name[NAMELEN-1] = 0; 300 cprint("%s->name (%s) not terminated\n", name, d->name); 301 return 0; 302 } 303 ns += i; 304 if(ns >= sizname){ 305 cprint("%s->name (%s) name too large\n", name, d->name); 306 return 0; 307 } 308 strcat(name, d->name); 309 310 if(d->mode & DDIR){ 311 if(ns > 1) 312 strcat(name, "/"); 313 if(flags & Cpdir) 314 cprint("%s\n", name); 315 } else 316 if(flags & Cpfile) 317 cprint("%s\n", name); 318 319 qpath = d->qid.path & ~QPDIR; 320 qmark(qpath); 321 if(qpath > maxq) 322 maxq = qpath; 323 for(i=0; i<NDBLOCK; i++) { 324 a = d->dblock[i]; 325 if(!a) 326 continue; 327 if(amark(a)) { 328 d->dblock[i] = 0; 329 dmod++; 330 continue; 331 } 332 if(d->mode & DDIR) 333 dmod += checkdir(a, qpath); 334 else if(flags & Crdall) 335 xread(a, qpath); 336 } 337 a = d->iblock; 338 if(a && amark(a)) { 339 d->iblock = 0; 340 dmod++; 341 } 342 else if(a) 343 dmod += checkindir(a, d, qpath); 344 345 a = d->diblock; 346 if(a && amark(a)) { 347 d->diblock = 0; 348 return dmod + 1; 349 } 350 dmod += touch(a); 351 if(p = xtag(a, Tind2, qpath)){ 352 for(i=0; i<INDPERBUF; i++){ 353 a = ((long*)p->iobuf)[i]; 354 if(!a) 355 continue; 356 if(amark(a)) { 357 if(flags & Cbad) { 358 ((long*)p->iobuf)[i] = 0; 359 p->flags |= Bmod; 360 } 361 continue; 362 } 363 dmod += checkindir(a, d, qpath); 364 } 365 putbuf(p); 366 } 367 return dmod; 368 } 369 370 static 371 void 372 ckfreelist(Superb *sb) 373 { 374 long a, lo, hi; 375 int n, i; 376 Iobuf *p; 377 Fbuf *fb; 378 379 380 strcpy(name, "free list"); 381 cprint("check %s\n", name); 382 fb = &sb->fbuf; 383 a = sbaddr; 384 p = 0; 385 lo = 0; 386 hi = 0; 387 for(;;) { 388 n = fb->nfree; 389 if(n < 0 || n > FEPERBUF) { 390 cprint("check: nfree bad %ld\n", a); 391 break; 392 } 393 for(i=1; i<n; i++) { 394 a = fb->free[i]; 395 if(a && !fmark(a)) { 396 if(!lo || lo > a) 397 lo = a; 398 if(!hi || hi < a) 399 hi = a; 400 } 401 } 402 a = fb->free[0]; 403 if(!a) 404 break; 405 if(fmark(a)) 406 break; 407 if(!lo || lo > a) 408 lo = a; 409 if(!hi || hi < a) 410 hi = a; 411 if(p) 412 putbuf(p); 413 p = xtag(a, Tfree, QPNONE); 414 if(!p) 415 break; 416 fb = (Fbuf*)p->iobuf; 417 } 418 if(p) 419 putbuf(p); 420 cprint("lo = %ld; hi = %ld\n", lo, hi); 421 } 422 423 /* 424 * make freelist from scratch 425 */ 426 static 427 void 428 mkfreelist(Superb *sb) 429 { 430 long a; 431 int i, b; 432 433 strcpy(name, "free list"); 434 memset(&sb->fbuf, 0, sizeof(sb->fbuf)); 435 sb->fbuf.nfree = 1; 436 sb->tfree = 0; 437 for(a=fsize-fstart-1; a >= 0; a--) { 438 i = a/8; 439 if(i < 0 || i >= sizabits) 440 continue; 441 b = 1 << (a&7); 442 if(abits[i] & b) 443 continue; 444 addfree(dev, fstart+a, sb); 445 abits[i] |= b; 446 } 447 } 448 449 static 450 Dentry* 451 maked(long a, int s, long qpath) 452 { 453 Iobuf *p; 454 Dentry *d, *d1; 455 456 p = xtag(a, Tdir, qpath); 457 if(!p) 458 return 0; 459 d = getdir(p, s); 460 d1 = dalloc(sizeof(Dentry)); 461 memmove(d1, d, sizeof(Dentry)); 462 putbuf(p); 463 return d1; 464 } 465 466 static 467 void 468 modd(long a, int s, Dentry *d1) 469 { 470 Iobuf *p; 471 Dentry *d; 472 473 if(!(flags & Cbad)) 474 return; 475 p = getbuf(dev, a, Bread); 476 d = getdir(p, s); 477 if(!d) { 478 if(p) 479 putbuf(p); 480 return; 481 } 482 memmove(d, d1, sizeof(Dentry)); 483 p->flags |= Bmod; 484 putbuf(p); 485 } 486 487 static 488 void 489 xread(long a, long qpath) 490 { 491 Iobuf *p; 492 493 p = xtag(a, Tfile, qpath); 494 if(p) 495 putbuf(p); 496 } 497 498 static 499 Iobuf* 500 xtag(long a, int tag, long qpath) 501 { 502 Iobuf *p; 503 504 if(a == 0) 505 return 0; 506 p = getbuf(dev, a, Bread); 507 if(!p) { 508 cprint("check: \"%s\": xtag: p null\n", name); 509 if(flags & (Cream|Ctag)) { 510 p = getbuf(dev, a, Bmod); 511 if(p) { 512 memset(p->iobuf, 0, RBUFSIZE); 513 settag(p, tag, qpath); 514 mod++; 515 return p; 516 } 517 } 518 return 0; 519 } 520 if(checktag(p, tag, qpath)) { 521 cprint("check: \"%s\": xtag: checktag\n", name); 522 if(flags & Cream) 523 memset(p->iobuf, 0, RBUFSIZE); 524 if(flags & (Cream|Ctag)) { 525 settag(p, tag, qpath); 526 mod++; 527 } 528 return p; 529 } 530 return p; 531 } 532 533 static 534 int 535 amark(long a) 536 { 537 long i; 538 int b; 539 540 if(a < fstart || a >= fsize) { 541 cprint("check: \"%s\": range %ld\n", 542 name, a); 543 nbad++; 544 return 1; 545 } 546 a -= fstart; 547 i = a/8; 548 b = 1 << (a&7); 549 if(abits[i] & b) { 550 if(!ronly) { 551 if(ndup < 10) 552 cprint("check: \"%s\": address dup %ld\n", 553 name, fstart+a); 554 else 555 if(ndup == 10) 556 cprint("..."); 557 } 558 ndup++; 559 return 0; /* really?? */ 560 } 561 abits[i] |= b; 562 nused++; 563 return 0; 564 } 565 566 static 567 int 568 fmark(long a) 569 { 570 long i; 571 int b; 572 573 if(a < fstart || a >= fsize) { 574 cprint("check: \"%s\": range %ld\n", 575 name, a); 576 nbad++; 577 return 1; 578 } 579 a -= fstart; 580 i = a/8; 581 b = 1 << (a&7); 582 if(abits[i] & b) { 583 cprint("check: \"%s\": address dup %ld\n", 584 name, fstart+a); 585 nfdup++; 586 return 1; 587 } 588 abits[i] |= b; 589 nfree++; 590 return 0; 591 } 592 593 static 594 void 595 missing(void) 596 { 597 long a, i; 598 int b, n; 599 600 n = 0; 601 for(a=fsize-fstart-1; a>=0; a--) { 602 i = a/8; 603 b = 1 << (a&7); 604 if(!(abits[i] & b)) { 605 cprint("missing: %ld\n", fstart+a); 606 n++; 607 } 608 if(n > 10) { 609 cprint(" ...\n"); 610 break; 611 } 612 } 613 } 614 615 static 616 void 617 qmark(long qpath) 618 { 619 int i, b; 620 621 i = qpath/8; 622 b = 1 << (qpath&7); 623 if(i < 0 || i >= sizqbits) { 624 nqbad++; 625 if(nqbad < 20) 626 cprint("check: \"%s\": qid out of range %lux\n", 627 name, qpath); 628 return; 629 } 630 if((qbits[i] & b) && !ronly) { 631 nqbad++; 632 if(nqbad < 20) 633 cprint("check: \"%s\": qid dup %lux\n", 634 name, qpath); 635 } 636 qbits[i] |= b; 637 } 638