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