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 char *s; 286 Rune r; 287 Iobuf *p; 288 int l, i, ns, dmod; 289 long a, qpath; 290 291 depth++; 292 if(depth >= maxdepth){ 293 maxdepth = depth; 294 if(maxdepth >= MAXDEPTH){ 295 cprint("max depth exceeded: %s\n", name); 296 return 0; 297 } 298 } 299 dmod = 0; 300 if(!(d->mode & DALLOC)) 301 return 0; 302 nfiles++; 303 304 ns = strlen(name); 305 i = strlen(d->name); 306 if(i >= NAMELEN){ 307 d->name[NAMELEN-1] = 0; 308 cprint("%s->name (%s) not terminated\n", name, d->name); 309 return 0; 310 } 311 ns += i; 312 if(ns >= sizname){ 313 cprint("%s->name (%s) name too large\n", name, d->name); 314 return 0; 315 } 316 for (s = d->name; *s; s += l){ 317 l = chartorune(&r, s); 318 if (r == Runeerror) 319 for (i = 0; i < l; i++){ 320 s[i] = '_'; 321 cprint("%s->name (%s) bad UTF\n", name, d->name); 322 dmod++; 323 } 324 } 325 strcat(name, d->name); 326 327 if(d->mode & DDIR){ 328 if(ns > 1) 329 strcat(name, "/"); 330 if(flags & Cpdir) 331 cprint("%s\n", name); 332 } else 333 if(flags & Cpfile) 334 cprint("%s\n", name); 335 336 qpath = d->qid.path & ~QPDIR; 337 qmark(qpath); 338 if(qpath > maxq) 339 maxq = qpath; 340 for(i=0; i<NDBLOCK; i++) { 341 a = d->dblock[i]; 342 if(!a) 343 continue; 344 if(amark(a)) { 345 d->dblock[i] = 0; 346 dmod++; 347 continue; 348 } 349 if(d->mode & DDIR) 350 dmod += checkdir(a, qpath); 351 else if(flags & Crdall) 352 xread(a, qpath); 353 } 354 a = d->iblock; 355 if(a && amark(a)) { 356 d->iblock = 0; 357 dmod++; 358 } 359 else if(a) 360 dmod += checkindir(a, d, qpath); 361 362 a = d->diblock; 363 if(a && amark(a)) { 364 d->diblock = 0; 365 return dmod + 1; 366 } 367 dmod += touch(a); 368 if(p = xtag(a, Tind2, qpath)){ 369 for(i=0; i<INDPERBUF; i++){ 370 a = ((long*)p->iobuf)[i]; 371 if(!a) 372 continue; 373 if(amark(a)) { 374 if(flags & Cbad) { 375 ((long*)p->iobuf)[i] = 0; 376 p->flags |= Bmod; 377 } 378 continue; 379 } 380 dmod += checkindir(a, d, qpath); 381 } 382 putbuf(p); 383 } 384 return dmod; 385 } 386 387 static 388 void 389 ckfreelist(Superb *sb) 390 { 391 long a, lo, hi; 392 int n, i; 393 Iobuf *p; 394 Fbuf *fb; 395 396 397 strcpy(name, "free list"); 398 cprint("check %s\n", name); 399 fb = &sb->fbuf; 400 a = sbaddr; 401 p = 0; 402 lo = 0; 403 hi = 0; 404 for(;;) { 405 n = fb->nfree; 406 if(n < 0 || n > FEPERBUF) { 407 cprint("check: nfree bad %ld\n", a); 408 break; 409 } 410 for(i=1; i<n; i++) { 411 a = fb->free[i]; 412 if(a && !fmark(a)) { 413 if(!lo || lo > a) 414 lo = a; 415 if(!hi || hi < a) 416 hi = a; 417 } 418 } 419 a = fb->free[0]; 420 if(!a) 421 break; 422 if(fmark(a)) 423 break; 424 if(!lo || lo > a) 425 lo = a; 426 if(!hi || hi < a) 427 hi = a; 428 if(p) 429 putbuf(p); 430 p = xtag(a, Tfree, QPNONE); 431 if(!p) 432 break; 433 fb = (Fbuf*)p->iobuf; 434 } 435 if(p) 436 putbuf(p); 437 cprint("lo = %ld; hi = %ld\n", lo, hi); 438 } 439 440 /* 441 * make freelist from scratch 442 */ 443 static 444 void 445 mkfreelist(Superb *sb) 446 { 447 long a; 448 int i, b; 449 450 strcpy(name, "free list"); 451 memset(&sb->fbuf, 0, sizeof(sb->fbuf)); 452 sb->fbuf.nfree = 1; 453 sb->tfree = 0; 454 for(a=fsize-fstart-1; a >= 0; a--) { 455 i = a/8; 456 if(i < 0 || i >= sizabits) 457 continue; 458 b = 1 << (a&7); 459 if(abits[i] & b) 460 continue; 461 addfree(dev, fstart+a, sb); 462 abits[i] |= b; 463 } 464 } 465 466 static 467 Dentry* 468 maked(long a, int s, long qpath) 469 { 470 Iobuf *p; 471 Dentry *d, *d1; 472 473 p = xtag(a, Tdir, qpath); 474 if(!p) 475 return 0; 476 d = getdir(p, s); 477 d1 = dalloc(sizeof(Dentry)); 478 memmove(d1, d, sizeof(Dentry)); 479 putbuf(p); 480 return d1; 481 } 482 483 static 484 void 485 modd(long a, int s, Dentry *d1) 486 { 487 Iobuf *p; 488 Dentry *d; 489 490 if(!(flags & Cbad)) 491 return; 492 p = getbuf(dev, a, Bread); 493 d = getdir(p, s); 494 if(!d) { 495 if(p) 496 putbuf(p); 497 return; 498 } 499 memmove(d, d1, sizeof(Dentry)); 500 p->flags |= Bmod; 501 putbuf(p); 502 } 503 504 static 505 void 506 xread(long a, long qpath) 507 { 508 Iobuf *p; 509 510 p = xtag(a, Tfile, qpath); 511 if(p) 512 putbuf(p); 513 } 514 515 static 516 Iobuf* 517 xtag(long a, int tag, long qpath) 518 { 519 Iobuf *p; 520 521 if(a == 0) 522 return 0; 523 p = getbuf(dev, a, Bread); 524 if(!p) { 525 cprint("check: \"%s\": xtag: p null\n", name); 526 if(flags & (Cream|Ctag)) { 527 p = getbuf(dev, a, Bmod); 528 if(p) { 529 memset(p->iobuf, 0, RBUFSIZE); 530 settag(p, tag, qpath); 531 mod++; 532 return p; 533 } 534 } 535 return 0; 536 } 537 if(checktag(p, tag, qpath)) { 538 cprint("check: \"%s\": xtag: checktag\n", name); 539 if(flags & Cream) 540 memset(p->iobuf, 0, RBUFSIZE); 541 if(flags & (Cream|Ctag)) { 542 settag(p, tag, qpath); 543 mod++; 544 } 545 return p; 546 } 547 return p; 548 } 549 550 static 551 int 552 amark(long a) 553 { 554 long i; 555 int b; 556 557 if(a < fstart || a >= fsize) { 558 cprint("check: \"%s\": range %ld\n", 559 name, a); 560 nbad++; 561 return 1; 562 } 563 a -= fstart; 564 i = a/8; 565 b = 1 << (a&7); 566 if(abits[i] & b) { 567 if(!ronly) { 568 if(ndup < 10) 569 cprint("check: \"%s\": address dup %ld\n", 570 name, fstart+a); 571 else 572 if(ndup == 10) 573 cprint("..."); 574 } 575 ndup++; 576 return 0; /* really?? */ 577 } 578 abits[i] |= b; 579 nused++; 580 return 0; 581 } 582 583 static 584 int 585 fmark(long a) 586 { 587 long i; 588 int b; 589 590 if(a < fstart || a >= fsize) { 591 cprint("check: \"%s\": range %ld\n", 592 name, a); 593 nbad++; 594 return 1; 595 } 596 a -= fstart; 597 i = a/8; 598 b = 1 << (a&7); 599 if(abits[i] & b) { 600 cprint("check: \"%s\": address dup %ld\n", 601 name, fstart+a); 602 nfdup++; 603 return 1; 604 } 605 abits[i] |= b; 606 nfree++; 607 return 0; 608 } 609 610 static 611 void 612 missing(void) 613 { 614 long a, i; 615 int b, n; 616 617 n = 0; 618 for(a=fsize-fstart-1; a>=0; a--) { 619 i = a/8; 620 b = 1 << (a&7); 621 if(!(abits[i] & b)) { 622 cprint("missing: %ld\n", fstart+a); 623 n++; 624 } 625 if(n > 10) { 626 cprint(" ...\n"); 627 break; 628 } 629 } 630 } 631 632 static 633 void 634 qmark(long qpath) 635 { 636 int i, b; 637 638 i = qpath/8; 639 b = 1 << (qpath&7); 640 if(i < 0 || i >= sizqbits) { 641 nqbad++; 642 if(nqbad < 20) 643 cprint("check: \"%s\": qid out of range %lux\n", 644 name, qpath); 645 return; 646 } 647 if((qbits[i] & b) && !ronly) { 648 nqbad++; 649 if(nqbad < 20) 650 cprint("check: \"%s\": qid dup %lux\n", 651 name, qpath); 652 } 653 qbits[i] |= b; 654 } 655