1 /* 2 * cached-worm device 3 */ 4 #include "all.h" 5 6 #define CDEV(d) ((d)->cw.c) 7 #define WDEV(d) ((d)->cw.w) 8 #define RDEV(d) ((d)->cw.ro) 9 10 enum { 11 DEBUG = 0, 12 FIRST = SUPER_ADDR, 13 14 ADDFREE = 100, 15 CACHE_ADDR = SUPER_ADDR, 16 MAXAGE = 10000, 17 }; 18 19 /* cache state */ 20 enum 21 { 22 /* states -- beware these are recorded on the cache */ 23 /* cache worm */ 24 Cnone = 0, /* 0 ? */ 25 Cdirty, /* 1 0 */ 26 Cdump, /* 1 0->1 */ 27 Cread, /* 1 1 */ 28 Cwrite, /* 2 1 */ 29 Cdump1, /* inactive form of dump */ 30 Cerror, 31 32 /* opcodes -- these are not recorded */ 33 Onone, 34 Oread, 35 Owrite, 36 Ogrow, 37 Odump, 38 Orele, 39 Ofree, 40 }; 41 42 typedef struct Cw Cw; 43 struct Cw 44 { 45 Device* dev; 46 Device* cdev; 47 Device* wdev; 48 Device* rodev; 49 Cw* link; 50 51 int dbucket; /* last bucket dumped */ 52 Off daddr; /* last block dumped */ 53 Off ncopy; 54 int nodump; 55 /* 56 * following are cached variables for dumps 57 */ 58 Off fsize; 59 Off ndump; 60 int depth; 61 int all; /* local flag to recur on modified dirs */ 62 int allflag; /* global flag to recur on modified dirs */ 63 Off falsehits; /* times recur found modified blocks */ 64 struct { 65 char name[500]; 66 char namepad[NAMELEN+10]; 67 }; 68 }; 69 70 static char* cwnames[] = 71 { 72 [Cnone] "none", 73 [Cdirty] "dirty", 74 [Cdump] "dump", 75 [Cread] "read", 76 [Cwrite] "write", 77 [Cdump1] "dump1", 78 [Cerror] "error", 79 80 [Onone] "none", 81 [Oread] "read", 82 [Owrite] "write", 83 [Ogrow] "grow", 84 [Odump] "dump", 85 [Orele] "rele", 86 }; 87 88 int oldcachefmt = 1; 89 90 Centry* getcentry(Bucket*, Off); 91 int cwio(Device*, Off, void*, int); 92 void cmd_cwcmd(int, char*[]); 93 94 /* 95 * console command 96 * initiate a dump 97 */ 98 void 99 cmd_dump(int argc, char *argv[]) 100 { 101 Filsys *fs; 102 103 fs = cons.curfs; 104 if(argc > 1) 105 fs = fsstr(argv[1]); 106 if(fs == 0) { 107 print("%s: unknown file system\n", argv[1]); 108 return; 109 } 110 cfsdump(fs); 111 } 112 113 /* 114 * console command 115 * worm stats 116 */ 117 static void 118 cmd_statw(int, char*[]) 119 { 120 Filsys *fs; 121 Iobuf *p; 122 Superb *sb; 123 Cache *h; 124 Bucket *b; 125 Centry *c, *ce; 126 Off m, nw, bw, state[Onone]; 127 Off sbfsize, sbcwraddr, sbroraddr, sblast, sbnext; 128 Off hmsize, hmaddr, dsize, dsizepct; 129 Device *dev; 130 Cw *cw; 131 int s; 132 133 fs = cons.curfs; 134 dev = fs->dev; 135 if(dev->type != Devcw) { 136 print("curfs not type cw\n"); 137 return; 138 } 139 140 cw = dev->private; 141 if(cw == 0) { 142 print("curfs not inited\n"); 143 return; 144 } 145 146 print("cwstats %s\n", fs->name); 147 148 sbfsize = 0; 149 sbcwraddr = 0; 150 sbroraddr = 0; 151 sblast = 0; 152 sbnext = 0; 153 154 print("\tfilesys %s\n", fs->name); 155 // print("\tnio =%7W%7W%7W\n", cw->ncwio+0, cw->ncwio+1, cw->ncwio+2); 156 p = getbuf(dev, cwsaddr(dev), Brd); 157 if(!p || checktag(p, Tsuper, QPSUPER)) { 158 print("cwstats: checktag super\n"); 159 if(p) { 160 putbuf(p); 161 p = 0; 162 } 163 } 164 if(p) { 165 sb = (Superb*)p->iobuf; 166 sbfsize = sb->fsize; 167 sbcwraddr = sb->cwraddr; 168 sbroraddr = sb->roraddr; 169 sblast = sb->last; 170 sbnext = sb->next; 171 putbuf(p); 172 } 173 174 p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres); 175 if(!p || checktag(p, Tcache, QPSUPER)) { 176 print("cwstats: checktag c bucket\n"); 177 if(p) 178 putbuf(p); 179 return; 180 } 181 h = (Cache*)p->iobuf; 182 hmaddr = h->maddr; 183 hmsize = h->msize; 184 185 print("\t\tmaddr = %8lld\n", (Wideoff)hmaddr); 186 print("\t\tmsize = %8lld\n", (Wideoff)hmsize); 187 print("\t\tcaddr = %8lld\n", (Wideoff)h->caddr); 188 print("\t\tcsize = %8lld\n", (Wideoff)h->csize); 189 print("\t\tsbaddr = %8lld\n", (Wideoff)h->sbaddr); 190 print("\t\tcraddr = %8lld %8lld\n", 191 (Wideoff)h->cwraddr, (Wideoff)sbcwraddr); 192 print("\t\troaddr = %8lld %8lld\n", 193 (Wideoff)h->roraddr, (Wideoff)sbroraddr); 194 /* print stats in terms of (first-)disc sides */ 195 dsize = wormsizeside(dev, 0); 196 if (dsize < 1) { 197 if (DEBUG) 198 print("wormsizeside returned size %lld for %Z side 0\n", 199 (Wideoff)dsize, dev); 200 dsize = h->wsize; /* it's probably a fake worm */ 201 if (dsize < 1) 202 dsize = 1000; /* don't divide by zero */ 203 } 204 dsizepct = dsize/100; 205 print("\t\tfsize = %8lld %8lld %2lld+%2lld%%\n", (Wideoff)h->fsize, 206 (Wideoff)sbfsize, (Wideoff)h->fsize/dsize, 207 (Wideoff)(h->fsize%dsize)/dsizepct); 208 print("\t\tslast = %8lld\n", (Wideoff)sblast); 209 print("\t\tsnext = %8lld\n", (Wideoff)sbnext); 210 print("\t\twmax = %8lld %2lld+%2lld%%\n", 211 (Wideoff)h->wmax, (Wideoff)h->wmax/dsize, 212 (Wideoff)(h->wmax%dsize)/dsizepct); 213 print("\t\twsize = %8lld %2lld+%2lld%%\n", 214 (Wideoff)h->wsize, (Wideoff)h->wsize/dsize, 215 (Wideoff)(h->wsize%dsize)/dsizepct); 216 putbuf(p); 217 218 bw = 0; /* max filled bucket */ 219 memset(state, 0, sizeof(state)); 220 for(m = 0; m < hmsize; m++) { 221 p = getbuf(cw->cdev, hmaddr + m/BKPERBLK, Brd); 222 if(!p || checktag(p, Tbuck, hmaddr + m/BKPERBLK)) { 223 print("cwstats: checktag c bucket\n"); 224 if(p) 225 putbuf(p); 226 return; 227 } 228 b = (Bucket*)p->iobuf + m%BKPERBLK; 229 ce = b->entry + CEPERBK; 230 nw = 0; 231 for(c = b->entry; c < ce; c++) { 232 s = c->state; 233 state[s]++; 234 if(s != Cnone && s != Cread) 235 nw++; 236 } 237 putbuf(p); 238 if(nw > bw) 239 bw = nw; 240 } 241 for(s = Cnone; s < Cerror; s++) 242 print("\t\t%6lld %s\n", (Wideoff)state[s], cwnames[s]); 243 print("\t\tcache %2lld%% full\n", ((Wideoff)bw*100)/CEPERBK); 244 } 245 246 int 247 dumpblock(Device *dev) 248 { 249 Iobuf *p, *cb, *p1, *p2; 250 Cache *h; 251 Centry *c, *ce, *bc; 252 Bucket *b; 253 Off m, a, msize, maddr, wmax, caddr; 254 int s1, s2, count; 255 Cw *cw; 256 257 cw = dev->private; 258 if(cw == 0 || cw->nodump) 259 return 0; 260 261 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres); 262 h = (Cache*)cb->iobuf; 263 msize = h->msize; 264 maddr = h->maddr; 265 wmax = h->wmax; 266 caddr = h->caddr; 267 putbuf(cb); 268 269 for(m=msize; m>=0; m--) { 270 a = cw->dbucket + 1; 271 if(a < 0 || a >= msize) 272 a = 0; 273 cw->dbucket = a; 274 p = getbuf(cw->cdev, maddr + a/BKPERBLK, Brd); 275 b = (Bucket*)p->iobuf + a%BKPERBLK; 276 ce = b->entry + CEPERBK; 277 bc = 0; 278 for(c = b->entry; c < ce; c++) 279 if(c->state == Cdump) { 280 if(bc == 0) { 281 bc = c; 282 continue; 283 } 284 if(c->waddr < cw->daddr) { 285 if(bc->waddr < cw->daddr && 286 bc->waddr > c->waddr) 287 bc = c; 288 continue; 289 } 290 if(bc->waddr < cw->daddr || 291 bc->waddr > c->waddr) 292 bc = c; 293 } 294 if(bc) { 295 c = bc; 296 goto found; 297 } 298 putbuf(p); 299 } 300 if(cw->ncopy) { 301 print("%lld blocks copied to worm\n", (Wideoff)cw->ncopy); 302 cw->ncopy = 0; 303 } 304 cw->nodump = 1; 305 return 0; 306 307 found: 308 if (oldcachefmt) 309 a = a*CEPERBK + (c - b->entry) + caddr; 310 else 311 a += (c - b->entry)*msize + caddr; 312 p1 = getbuf(devnone, Cwdump1, 0); 313 count = 0; 314 315 retry: 316 count++; 317 if(count > 10 || devread(cw->cdev, a, p1->iobuf)) 318 goto stop; 319 m = c->waddr; 320 cw->daddr = m; 321 s1 = devwrite(cw->wdev, m, p1->iobuf); 322 if(s1) { 323 p2 = getbuf(devnone, Cwdump2, 0); 324 s2 = devread(cw->wdev, m, p2->iobuf); 325 if(s2) { 326 if(s1 == 0x61 && s2 == 0x60) { 327 putbuf(p2); 328 goto retry; 329 } 330 goto stop1; 331 } 332 if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) 333 goto stop1; 334 putbuf(p2); 335 } 336 /* 337 * reread and compare 338 */ 339 if(conf.dumpreread) { 340 p2 = getbuf(devnone, Cwdump2, 0); 341 s1 = devread(cw->wdev, m, p2->iobuf); 342 if(s1) 343 goto stop1; 344 if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) { 345 print("reread C%lld W%lld didnt compare\n", 346 (Wideoff)a, (Wideoff)m); 347 goto stop1; 348 } 349 putbuf(p2); 350 } 351 352 putbuf(p1); 353 c->state = Cread; 354 p->flags |= Bmod; 355 putbuf(p); 356 357 if(m > wmax) { 358 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres); 359 h = (Cache*)cb->iobuf; 360 if(m > h->wmax) 361 h->wmax = m; 362 putbuf(cb); 363 } 364 cw->ncopy++; 365 return 1; 366 367 stop1: 368 putbuf(p2); 369 putbuf(p1); 370 c->state = Cdump1; 371 p->flags |= Bmod; 372 putbuf(p); 373 return 1; 374 375 stop: 376 putbuf(p1); 377 putbuf(p); 378 print("stopping dump!!\n"); 379 cw->nodump = 1; 380 return 0; 381 } 382 383 void 384 cwinit1(Device *dev) 385 { 386 Cw *cw; 387 static int first; 388 389 cw = dev->private; 390 if(cw) 391 return; 392 393 if(first == 0) { 394 cmd_install("dump", "-- make dump backup to worm", cmd_dump); 395 cmd_install("statw", "-- cache/worm stats", cmd_statw); 396 cmd_install("cwcmd", "subcommand -- cache/worm errata", cmd_cwcmd); 397 roflag = flag_install("ro", "-- ro reads and writes"); 398 first = 1; 399 } 400 cw = malloc(sizeof(Cw)); 401 dev->private = cw; 402 403 cw->allflag = 0; 404 405 cw->dev = dev; 406 cw->cdev = CDEV(dev); 407 cw->wdev = WDEV(dev); 408 cw->rodev = RDEV(dev); 409 410 devinit(cw->cdev); 411 devinit(cw->wdev); 412 } 413 414 void 415 cwinit(Device *dev) 416 { 417 Cw *cw; 418 Cache *h; 419 Iobuf *cb, *p; 420 Off l, m; 421 422 cwinit1(dev); 423 424 cw = dev->private; 425 l = devsize(cw->wdev); 426 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres); 427 h = (Cache*)cb->iobuf; 428 h->toytime = toytime() + SECOND(30); 429 h->time = time(nil); 430 m = h->wsize; 431 if(l != m) { 432 print("wdev changed size %lld to %lld\n", 433 (Wideoff)m, (Wideoff)l); 434 h->wsize = l; 435 cb->flags |= Bmod; 436 } 437 438 for(m=0; m<h->msize; m++) { 439 p = getbuf(cw->cdev, h->maddr + m/BKPERBLK, Brd); 440 if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK)) 441 panic("cwinit: checktag c bucket"); 442 putbuf(p); 443 } 444 putbuf(cb); 445 } 446 447 Off 448 cwsaddr(Device *dev) 449 { 450 Iobuf *cb; 451 Off sa; 452 453 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); 454 sa = ((Cache*)cb->iobuf)->sbaddr; 455 putbuf(cb); 456 return sa; 457 } 458 459 Off 460 cwraddr(Device *dev) 461 { 462 Iobuf *cb; 463 Off ra; 464 465 switch(dev->type) { 466 default: 467 print("unknown dev in cwraddr %Z\n", dev); 468 return 1; 469 470 case Devcw: 471 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); 472 ra = ((Cache*)cb->iobuf)->cwraddr; 473 break; 474 475 case Devro: 476 cb = getbuf(CDEV(dev->ro.parent), CACHE_ADDR, Brd|Bres); 477 ra = ((Cache*)cb->iobuf)->roraddr; 478 break; 479 } 480 putbuf(cb); 481 return ra; 482 } 483 484 Devsize 485 cwsize(Device *dev) 486 { 487 Iobuf *cb; 488 Devsize fs; 489 490 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); 491 fs = ((Cache*)cb->iobuf)->fsize; 492 putbuf(cb); 493 return fs; 494 } 495 496 int 497 cwread(Device *dev, Off b, void *c) 498 { 499 return cwio(dev, b, c, Oread) == Cerror; 500 } 501 502 int 503 cwwrite(Device *dev, Off b, void *c) 504 { 505 return cwio(dev, b, c, Owrite) == Cerror; 506 } 507 508 int 509 roread(Device *dev, Off b, void *c) 510 { 511 Device *d; 512 int s; 513 514 /* 515 * maybe better is to try buffer pool first 516 */ 517 d = dev->ro.parent; 518 if(d == 0 || d->type != Devcw || 519 d->private == 0 || RDEV(d) != dev) { 520 print("bad rodev %Z\n", dev); 521 return 1; 522 } 523 s = cwio(d, b, 0, Onone); 524 if(s == Cdump || s == Cdump1 || s == Cread) { 525 s = cwio(d, b, c, Oread); 526 if(s == Cdump || s == Cdump1 || s == Cread) { 527 if(cons.flags & roflag) 528 print("roread: %Z %lld -> %Z(hit)\n", 529 dev, (Wideoff)b, d); 530 return 0; 531 } 532 } 533 if(cons.flags & roflag) 534 print("roread: %Z %lld -> %Z(miss)\n", 535 dev, (Wideoff)b, WDEV(d)); 536 return devread(WDEV(d), b, c); 537 } 538 539 int 540 cwio(Device *dev, Off addr, void *buf, int opcode) 541 { 542 Iobuf *p, *p1, *p2, *cb; 543 Cache *h; 544 Bucket *b; 545 Centry *c; 546 Off bn, a1, a2, max, newmax; 547 int state; 548 Cw *cw; 549 550 cw = dev->private; 551 552 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres); 553 h = (Cache*)cb->iobuf; 554 if(toytime() >= h->toytime) { 555 cb->flags |= Bmod; 556 h->toytime = toytime() + SECOND(30); 557 h->time = time(nil); 558 } 559 560 if(addr < 0) { 561 putbuf(cb); 562 return Cerror; 563 } 564 565 bn = addr % h->msize; 566 a1 = h->maddr + bn/BKPERBLK; 567 if (oldcachefmt) 568 a2 = bn*CEPERBK + h->caddr; 569 else 570 a2 = bn + h->caddr; 571 max = h->wmax; 572 573 putbuf(cb); 574 newmax = 0; 575 576 p = getbuf(cw->cdev, a1, Brd|Bmod); 577 if(!p || checktag(p, Tbuck, a1)) 578 panic("cwio: checktag c bucket"); 579 b = (Bucket*)p->iobuf + bn%BKPERBLK; 580 581 c = getcentry(b, addr); 582 if(c == 0) { 583 putbuf(p); 584 print("%Z disk cache bucket %lld is full\n", 585 cw->cdev, (Wideoff)a1); 586 return Cerror; 587 } 588 if (oldcachefmt) 589 a2 += c - b->entry; 590 else 591 a2 += (c - b->entry) * h->msize; 592 593 state = c->state; 594 switch(opcode) { 595 default: 596 goto bad; 597 598 case Onone: 599 break; 600 601 case Oread: 602 switch(state) { 603 default: 604 goto bad; 605 606 case Cread: 607 if(!devread(cw->cdev, a2, buf)) 608 break; 609 c->state = Cnone; 610 611 case Cnone: 612 if(devread(cw->wdev, addr, buf)) { 613 state = Cerror; 614 break; 615 } 616 if(addr > max) 617 newmax = addr; 618 if(!devwrite(cw->cdev, a2, buf)) 619 c->state = Cread; 620 break; 621 622 case Cdirty: 623 case Cdump: 624 case Cdump1: 625 case Cwrite: 626 if(devread(cw->cdev, a2, buf)) 627 state = Cerror; 628 break; 629 } 630 break; 631 632 case Owrite: 633 switch(state) { 634 default: 635 goto bad; 636 637 case Cdump: 638 case Cdump1: 639 /* 640 * this is hard part -- a dump block must be 641 * sent to the worm if it is rewritten. 642 * if this causes an error, there is no 643 * place to save the dump1 data. the block 644 * is just reclassified as 'dump1' (botch) 645 */ 646 p1 = getbuf(devnone, Cwio1, 0); 647 if(devread(cw->cdev, a2, p1->iobuf)) { 648 putbuf(p1); 649 print("cwio: write induced dump error - r cache\n"); 650 651 casenone: 652 if(devwrite(cw->cdev, a2, buf)) { 653 state = Cerror; 654 break; 655 } 656 c->state = Cdump1; 657 break; 658 } 659 if(devwrite(cw->wdev, addr, p1->iobuf)) { 660 p2 = getbuf(devnone, Cwio2, 0); 661 if(devread(cw->wdev, addr, p2->iobuf)) { 662 putbuf(p1); 663 putbuf(p2); 664 print("cwio: write induced dump error - r+w worm\n"); 665 goto casenone; 666 } 667 if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) { 668 putbuf(p1); 669 putbuf(p2); 670 print("cwio: write induced dump error - w worm\n"); 671 goto casenone; 672 } 673 putbuf(p2); 674 } 675 putbuf(p1); 676 c->state = Cread; 677 if(addr > max) 678 newmax = addr; 679 cw->ncopy++; 680 681 case Cnone: 682 case Cread: 683 if(devwrite(cw->cdev, a2, buf)) { 684 state = Cerror; 685 break; 686 } 687 c->state = Cwrite; 688 break; 689 690 case Cdirty: 691 case Cwrite: 692 if(devwrite(cw->cdev, a2, buf)) 693 state = Cerror; 694 break; 695 } 696 break; 697 698 case Ogrow: 699 if(state != Cnone) { 700 print("%Z for block %lld cwgrow with state = %s\n", 701 cw->cdev, (Wideoff)addr, cwnames[state]); 702 break; 703 } 704 c->state = Cdirty; 705 break; 706 707 case Odump: 708 if(state != Cdirty) { /* BOTCH */ 709 print("%Z for block %lld cwdump with state = %s\n", 710 cw->cdev, (Wideoff)addr, cwnames[state]); 711 break; 712 } 713 c->state = Cdump; 714 cw->ndump++; /* only called from dump command */ 715 break; 716 717 case Orele: 718 if(state != Cwrite) { 719 if(state != Cdump1) 720 print("%Z for block %lld cwrele with state = %s\n", 721 cw->cdev, (Wideoff)addr, cwnames[state]); 722 break; 723 } 724 c->state = Cnone; 725 break; 726 727 case Ofree: 728 if(state == Cwrite || state == Cread) 729 c->state = Cnone; 730 break; 731 } 732 if(DEBUG) 733 print("cwio: %Z %lld s=%s o=%s ns=%s\n", 734 dev, (Wideoff)addr, cwnames[state], 735 cwnames[opcode], 736 cwnames[c->state]); 737 putbuf(p); 738 if(newmax) { 739 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres); 740 h = (Cache*)cb->iobuf; 741 if(newmax > h->wmax) 742 h->wmax = newmax; 743 putbuf(cb); 744 } 745 return state; 746 747 bad: 748 print("%Z block %lld cw state = %s; cw opcode = %s", 749 dev, (Wideoff)addr, cwnames[state], cwnames[opcode]); 750 return Cerror; 751 } 752 753 754 int 755 cwgrow(Device *dev, Superb *sb, int uid) 756 { 757 char str[NAMELEN]; 758 Iobuf *cb; 759 Cache *h; 760 Filsys *filsys; 761 Off fs, nfs, ws; 762 763 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bmod|Bres); 764 h = (Cache*)cb->iobuf; 765 ws = h->wsize; 766 fs = h->fsize; 767 if(fs >= ws) 768 return 0; 769 nfs = fs + ADDFREE; 770 if(nfs >= ws) 771 nfs = ws; 772 h->fsize = nfs; 773 putbuf(cb); 774 775 sb->fsize = nfs; 776 filsys = dev2fs(dev); 777 if (filsys == nil) 778 print("%Z", dev); 779 else 780 print("%s", filsys->name); 781 uidtostr(str, uid, 1); 782 print(" grow from %lld to %lld limit %lld by %s uid=%d\n", 783 (Wideoff)fs, (Wideoff)nfs, (Wideoff)ws, str, uid); 784 for(nfs--; nfs>=fs; nfs--) 785 switch(cwio(dev, nfs, 0, Ogrow)) { 786 case Cerror: 787 return 0; 788 case Cnone: 789 addfree(dev, nfs, sb); 790 } 791 return 1; 792 } 793 794 int 795 cwfree(Device *dev, Off addr) 796 { 797 int state; 798 799 if(dev->type == Devcw) { 800 state = cwio(dev, addr, 0, Ofree); 801 if(state != Cdirty) 802 return 1; /* do not put in freelist */ 803 } 804 return 0; /* put in freelist */ 805 } 806 807 #ifdef unused 808 int 809 bktcheck(Bucket *b) 810 { 811 Centry *c, *c1, *c2, *ce; 812 int err; 813 814 err = 0; 815 if(b->agegen < CEPERBK || b->agegen > MAXAGE) { 816 print("agegen %ld\n", b->agegen); 817 err = 1; 818 } 819 820 ce = b->entry + CEPERBK; 821 c1 = 0; /* lowest age last pass */ 822 for(;;) { 823 c2 = 0; /* lowest age this pass */ 824 for(c = b->entry; c < ce; c++) { 825 if(c1 != 0 && c != c1) { 826 if(c->age == c1->age) { 827 print("same age %d\n", c->age); 828 err = 1; 829 } 830 if(c1->waddr == c->waddr) 831 if(c1->state != Cnone) 832 if(c->state != Cnone) { 833 print("same waddr %lld\n", 834 (Wideoff)c->waddr); 835 err = 1; 836 } 837 } 838 if(c1 != 0 && c->age <= c1->age) 839 continue; 840 if(c2 == 0 || c->age < c2->age) 841 c2 = c; 842 } 843 if(c2 == 0) 844 break; 845 c1 = c2; 846 if(c1->age >= b->agegen) { 847 print("age >= generator %d %ld\n", c1->age, b->agegen); 848 err = 1; 849 } 850 } 851 return err; 852 } 853 #endif 854 855 void 856 resequence(Bucket *b) 857 { 858 Centry *c, *ce, *cr; 859 int age, i; 860 861 ce = b->entry + CEPERBK; 862 for(c = b->entry; c < ce; c++) { 863 c->age += CEPERBK; 864 if(c->age < CEPERBK) 865 c->age = MAXAGE; 866 } 867 b->agegen += CEPERBK; 868 869 age = 0; 870 for(i=0;; i++) { 871 cr = 0; 872 for(c = b->entry; c < ce; c++) { 873 if(c->age < i) 874 continue; 875 if(cr == 0 || c->age < age) { 876 cr = c; 877 age = c->age; 878 } 879 } 880 if(cr == 0) 881 break; 882 cr->age = i; 883 } 884 b->agegen = i; 885 cons.nreseq++; 886 } 887 888 Centry* 889 getcentry(Bucket *b, Off addr) 890 { 891 Centry *c, *ce, *cr; 892 int s, age; 893 894 /* 895 * search for cache hit 896 * find oldest block as byproduct 897 */ 898 ce = b->entry + CEPERBK; 899 age = 0; 900 cr = 0; 901 for(c = b->entry; c < ce; c++) { 902 s = c->state; 903 if(s == Cnone) { 904 cr = c; 905 age = 0; 906 continue; 907 } 908 if(c->waddr == addr) 909 goto found; 910 if(s == Cread) 911 if(cr == 0 || c->age < age) { 912 cr = c; 913 age = c->age; 914 } 915 } 916 917 /* 918 * remap entry 919 */ 920 c = cr; 921 if(c == 0) 922 return 0; /* bucket is full */ 923 924 c->state = Cnone; 925 c->waddr = addr; 926 927 found: 928 /* 929 * update the age to get filo cache. 930 * small number in age means old 931 */ 932 if(!cons.noage || c->state == Cnone) { 933 age = b->agegen; 934 c->age = age; 935 age++; 936 b->agegen = age; 937 if(age < 0 || age >= MAXAGE) 938 resequence(b); 939 } 940 return c; 941 } 942 943 /* 944 * ream the cache 945 * calculate new buckets 946 */ 947 Iobuf* 948 cacheinit(Device *dev) 949 { 950 Iobuf *cb, *p; 951 Cache *h; 952 Device *cdev; 953 Off m; 954 955 print("cache init %Z\n", dev); 956 cdev = CDEV(dev); 957 devinit(cdev); 958 959 cb = getbuf(cdev, CACHE_ADDR, Bmod|Bres); 960 memset(cb->iobuf, 0, RBUFSIZE); 961 settag(cb, Tcache, QPSUPER); 962 h = (Cache*)cb->iobuf; 963 964 /* 965 * calculate csize such that 966 * tsize = msize/BKPERBLK + csize and 967 * msize = csize/CEPERBK 968 */ 969 h->maddr = CACHE_ADDR + 1; 970 m = devsize(cdev) - h->maddr; 971 h->csize = ((Devsize)(m-1) * CEPERBK*BKPERBLK) / (CEPERBK*BKPERBLK+1); 972 h->msize = h->csize/CEPERBK - 5; 973 while(!prime(h->msize)) 974 h->msize--; 975 h->csize = h->msize*CEPERBK; 976 h->caddr = h->maddr + (h->msize+BKPERBLK-1)/BKPERBLK; 977 h->wsize = devsize(WDEV(dev)); 978 979 if(h->msize <= 0) 980 panic("cache too small"); 981 if(h->caddr + h->csize > m) 982 panic("cache size error"); 983 984 /* 985 * setup cache map 986 */ 987 for(m=h->maddr; m<h->caddr; m++) { 988 p = getbuf(cdev, m, Bmod); 989 memset(p->iobuf, 0, RBUFSIZE); 990 settag(p, Tbuck, m); 991 putbuf(p); 992 } 993 print("done cacheinit\n"); 994 return cb; 995 } 996 997 Off 998 getstartsb(Device *dev) 999 { 1000 Filsys *f; 1001 Startsb *s; 1002 1003 for(f=filsys; f->name; f++) 1004 if(devcmpr(f->dev, dev) == 0) { 1005 for(s=startsb; s->name; s++) 1006 if(strcmp(f->name, s->name) == 0) 1007 return s->startsb; 1008 print( 1009 "getstartsb: no special starting superblock for %Z %s\n", 1010 dev, f->name); 1011 return FIRST; 1012 } 1013 print("getstartsb: no filsys for device %Z\n", dev); 1014 return FIRST; 1015 } 1016 1017 /* 1018 * ream the cache 1019 * calculate new buckets 1020 * get superblock from 1021 * last worm dump block. 1022 */ 1023 void 1024 cwrecover(Device *dev) 1025 { 1026 Iobuf *p, *cb; 1027 Cache *h; 1028 Superb *s; 1029 Off m, baddr; 1030 Device *wdev; 1031 1032 // print("cwrecover %Z\n", dev); // DEBUG 1033 cwinit1(dev); 1034 wdev = WDEV(dev); 1035 1036 p = getbuf(devnone, Cwxx1, 0); 1037 s = (Superb*)p->iobuf; 1038 baddr = 0; 1039 m = getstartsb(dev); 1040 localconfinit(); 1041 if(conf.firstsb) 1042 m = conf.firstsb; 1043 for(;;) { 1044 memset(p->iobuf, 0, RBUFSIZE); 1045 if(devread(wdev, m, p->iobuf) || 1046 checktag(p, Tsuper, QPSUPER)) 1047 break; 1048 baddr = m; 1049 m = s->next; 1050 print("dump %lld is good; %lld next\n", (Wideoff)baddr, (Wideoff)m); 1051 if(baddr == conf.recovsb) 1052 break; 1053 } 1054 putbuf(p); 1055 if(!baddr) 1056 panic("recover: no superblock"); 1057 1058 p = getbuf(wdev, baddr, Brd); 1059 s = (Superb*)p->iobuf; 1060 1061 cb = cacheinit(dev); 1062 h = (Cache*)cb->iobuf; 1063 h->sbaddr = baddr; 1064 h->cwraddr = s->cwraddr; 1065 h->roraddr = s->roraddr; 1066 h->fsize = s->fsize + 100; /* this must be conservative */ 1067 if(conf.recovcw) 1068 h->cwraddr = conf.recovcw; 1069 if(conf.recovro) 1070 h->roraddr = conf.recovro; 1071 1072 putbuf(cb); 1073 putbuf(p); 1074 1075 p = getbuf(dev, baddr, Brd|Bmod); 1076 s = (Superb*)p->iobuf; 1077 1078 memset(&s->fbuf, 0, sizeof(s->fbuf)); 1079 s->fbuf.free[0] = 0; 1080 s->fbuf.nfree = 1; 1081 s->tfree = 0; 1082 if(conf.recovcw) 1083 s->cwraddr = conf.recovcw; 1084 if(conf.recovro) 1085 s->roraddr = conf.recovro; 1086 1087 putbuf(p); 1088 print("done recover\n"); 1089 } 1090 1091 /* 1092 * ream the cache 1093 * calculate new buckets 1094 * initialize superblock. 1095 */ 1096 void 1097 cwream(Device *dev) 1098 { 1099 Iobuf *p, *cb; 1100 Cache *h; 1101 Superb *s; 1102 Off m, baddr; 1103 Device *cdev; 1104 1105 print("cwream %Z\n", dev); 1106 cwinit1(dev); 1107 cdev = CDEV(dev); 1108 devinit(cdev); 1109 1110 baddr = FIRST; /* baddr = super addr 1111 baddr+1 = cw root 1112 baddr+2 = ro root 1113 baddr+3 = reserved next superblock */ 1114 1115 cb = cacheinit(dev); 1116 h = (Cache*)cb->iobuf; 1117 1118 h->sbaddr = baddr; 1119 h->cwraddr = baddr+1; 1120 h->roraddr = baddr+2; 1121 h->fsize = 0; /* prevents superream from freeing */ 1122 1123 putbuf(cb); 1124 1125 for(m=0; m<3; m++) 1126 cwio(dev, baddr+m, 0, Ogrow); 1127 superream(dev, baddr); 1128 rootream(dev, baddr+1); /* cw root */ 1129 rootream(dev, baddr+2); /* ro root */ 1130 1131 cb = getbuf(cdev, CACHE_ADDR, Brd|Bmod|Bres); 1132 h = (Cache*)cb->iobuf; 1133 h->fsize = baddr+4; 1134 putbuf(cb); 1135 1136 p = getbuf(dev, baddr, Brd|Bmod|Bimm); 1137 s = (Superb*)p->iobuf; 1138 s->last = baddr; 1139 s->cwraddr = baddr+1; 1140 s->roraddr = baddr+2; 1141 s->next = baddr+3; 1142 s->fsize = baddr+4; 1143 putbuf(p); 1144 1145 for(m=0; m<3; m++) 1146 cwio(dev, baddr+m, 0, Odump); 1147 } 1148 1149 Off 1150 rewalk1(Cw *cw, Off addr, int slot, Wpath *up) 1151 { 1152 Iobuf *p, *p1; 1153 Dentry *d; 1154 1155 if(up == 0) 1156 return cwraddr(cw->dev); 1157 up->addr = rewalk1(cw, up->addr, up->slot, up->up); 1158 p = getbuf(cw->dev, up->addr, Brd|Bmod); 1159 d = getdir(p, up->slot); 1160 if(!d || !(d->mode & DALLOC)) { 1161 print("rewalk1 1\n"); 1162 if(p) 1163 putbuf(p); 1164 return addr; 1165 } 1166 p1 = dnodebuf(p, d, slot/DIRPERBUF, 0, 0); 1167 if(!p1) { 1168 print("rewalk1 2\n"); 1169 if(p) 1170 putbuf(p); 1171 return addr; 1172 } 1173 if(DEBUG) 1174 print("rewalk1 %lld to %lld \"%s\"\n", 1175 (Wideoff)addr, (Wideoff)p1->addr, d->name); 1176 addr = p1->addr; 1177 p1->flags |= Bmod; 1178 putbuf(p1); 1179 putbuf(p); 1180 return addr; 1181 } 1182 1183 Off 1184 rewalk2(Cw *cw, Off addr, int slot, Wpath *up) 1185 { 1186 Iobuf *p, *p1; 1187 Dentry *d; 1188 1189 if(up == 0) 1190 return cwraddr(cw->rodev); 1191 up->addr = rewalk2(cw, up->addr, up->slot, up->up); 1192 p = getbuf(cw->rodev, up->addr, Brd); 1193 d = getdir(p, up->slot); 1194 if(!d || !(d->mode & DALLOC)) { 1195 print("rewalk2 1\n"); 1196 if(p) 1197 putbuf(p); 1198 return addr; 1199 } 1200 p1 = dnodebuf(p, d, slot/DIRPERBUF, 0, 0); 1201 if(!p1) { 1202 print("rewalk2 2\n"); 1203 if(p) 1204 putbuf(p); 1205 return addr; 1206 } 1207 if(DEBUG) 1208 print("rewalk2 %lld to %lld \"%s\"\n", 1209 (Wideoff)addr, (Wideoff)p1->addr, d->name); 1210 addr = p1->addr; 1211 putbuf(p1); 1212 putbuf(p); 1213 return addr; 1214 } 1215 1216 void 1217 rewalk(Cw *cw) 1218 { 1219 int h; 1220 File *f; 1221 1222 for(h=0; h<nelem(flist); h++) 1223 for(f=flist[h]; f; f=f->next) { 1224 if(!f->fs) 1225 continue; 1226 if(cw->dev == f->fs->dev) 1227 f->addr = rewalk1(cw, f->addr, f->slot, f->wpath); 1228 else 1229 if(cw->rodev == f->fs->dev) 1230 f->addr = rewalk2(cw, f->addr, f->slot, f->wpath); 1231 } 1232 } 1233 1234 Off 1235 split(Cw *cw, Iobuf *p, Off addr) 1236 { 1237 Off na; 1238 int state; 1239 1240 na = 0; 1241 if(p && (p->flags & Bmod)) { 1242 p->flags |= Bimm; 1243 putbuf(p); 1244 p = 0; 1245 } 1246 state = cwio(cw->dev, addr, 0, Onone); /* read the state (twice?) */ 1247 switch(state) { 1248 default: 1249 panic("split: unknown state %s", cwnames[state]); 1250 1251 case Cerror: 1252 case Cnone: 1253 case Cdump: 1254 case Cread: 1255 break; 1256 1257 case Cdump1: 1258 case Cwrite: 1259 /* 1260 * botch.. could be done by relabeling 1261 */ 1262 if(!p) { 1263 p = getbuf(cw->dev, addr, Brd); 1264 if(!p) { 1265 print("split: null getbuf\n"); 1266 break; 1267 } 1268 } 1269 na = cw->fsize; 1270 cw->fsize = na+1; 1271 cwio(cw->dev, na, 0, Ogrow); 1272 cwio(cw->dev, na, p->iobuf, Owrite); 1273 cwio(cw->dev, na, 0, Odump); 1274 cwio(cw->dev, addr, 0, Orele); 1275 break; 1276 1277 case Cdirty: 1278 cwio(cw->dev, addr, 0, Odump); 1279 break; 1280 } 1281 if(p) 1282 putbuf(p); 1283 return na; 1284 } 1285 1286 int 1287 isdirty(Cw *cw, Iobuf *p, Off addr, int tag) 1288 { 1289 int s; 1290 1291 if(p && (p->flags & Bmod)) 1292 return 1; 1293 s = cwio(cw->dev, addr, 0, Onone); 1294 if(s == Cdirty || s == Cwrite) 1295 return 1; 1296 if(tag >= Tind1 && tag <= Tmaxind) 1297 /* botch, get these modified */ 1298 if(s != Cnone) 1299 return 1; 1300 return 0; 1301 } 1302 1303 Off 1304 cwrecur(Cw *cw, Off addr, int tag, int tag1, long qp) 1305 { 1306 Iobuf *p; 1307 Dentry *d; 1308 int i, j, shouldstop; 1309 Off na; 1310 char *np; 1311 1312 shouldstop = 0; 1313 p = getbuf(cw->dev, addr, Bprobe); 1314 if(!isdirty(cw, p, addr, tag)) { 1315 if(!cw->all) { 1316 if(DEBUG) 1317 print("cwrecur: %lld t=%s not dirty %s\n", 1318 (Wideoff)addr, tagnames[tag], cw->name); 1319 if(p) 1320 putbuf(p); 1321 return 0; 1322 } 1323 shouldstop = 1; 1324 } 1325 if(DEBUG) 1326 print("cwrecur: %lld t=%s %s\n", 1327 (Wideoff)addr, tagnames[tag], cw->name); 1328 if(cw->depth >= 100) { 1329 print("dump depth too great %s\n", cw->name); 1330 if(p) 1331 putbuf(p); 1332 return 0; 1333 } 1334 cw->depth++; 1335 1336 switch(tag) { 1337 default: 1338 print("cwrecur: unknown tag %d %s\n", tag, cw->name); 1339 1340 case Tfile: 1341 break; 1342 1343 case Tsuper: 1344 case Tdir: 1345 if(!p) { 1346 p = getbuf(cw->dev, addr, Brd); 1347 if(!p) { 1348 print("cwrecur: Tdir p null %s\n", 1349 cw->name); 1350 break; 1351 } 1352 } 1353 if(tag == Tdir) { 1354 cw->namepad[0] = 0; /* force room */ 1355 np = strchr(cw->name, 0); 1356 *np++ = '/'; 1357 } else { 1358 np = 0; /* set */ 1359 cw->name[0] = 0; 1360 } 1361 1362 for(i=0; i<DIRPERBUF; i++) { 1363 d = getdir(p, i); 1364 if(!(d->mode & DALLOC)) 1365 continue; 1366 qp = d->qid.path & ~QPDIR; 1367 if(tag == Tdir) 1368 strncpy(np, d->name, NAMELEN); 1369 else 1370 if(i > 0) 1371 print("cwrecur: root with >1 directory\n"); 1372 tag1 = Tfile; 1373 if(d->mode & DDIR) 1374 tag1 = Tdir; 1375 for(j=0; j<NDBLOCK; j++) { 1376 na = d->dblock[j]; 1377 if(na) { 1378 na = cwrecur(cw, na, tag1, 0, qp); 1379 if(na) { 1380 d->dblock[j] = na; 1381 p->flags |= Bmod; 1382 } 1383 } 1384 } 1385 for (j = 0; j < NIBLOCK; j++) { 1386 na = d->iblocks[j]; 1387 if(na) { 1388 na = cwrecur(cw, na, Tind1+j, tag1, qp); 1389 if(na) { 1390 d->iblocks[j] = na; 1391 p->flags |= Bmod; 1392 } 1393 } 1394 } 1395 } 1396 break; 1397 1398 case Tind1: 1399 j = tag1; 1400 tag1 = 0; 1401 goto tind; 1402 1403 case Tind2: 1404 #ifndef COMPAT32 1405 case Tind3: 1406 case Tind4: 1407 /* add more Tind tags here ... */ 1408 #endif 1409 j = tag-1; 1410 tind: 1411 if(!p) { 1412 p = getbuf(cw->dev, addr, Brd); 1413 if(!p) { 1414 print("cwrecur: Tind p null %s\n", cw->name); 1415 break; 1416 } 1417 } 1418 for(i=0; i<INDPERBUF; i++) { 1419 na = ((Off *)p->iobuf)[i]; 1420 if(na) { 1421 na = cwrecur(cw, na, j, tag1, qp); 1422 if(na) { 1423 ((Off *)p->iobuf)[i] = na; 1424 p->flags |= Bmod; 1425 } 1426 } 1427 } 1428 break; 1429 } 1430 na = split(cw, p, addr); 1431 cw->depth--; 1432 if(na && shouldstop) { 1433 if(cw->falsehits < 10) 1434 print("shouldstop %lld %lld t=%s %s\n", 1435 (Wideoff)addr, (Wideoff)na, 1436 tagnames[tag], cw->name); 1437 cw->falsehits++; 1438 } 1439 return na; 1440 } 1441 1442 Timet nextdump(Timet t); 1443 1444 void 1445 cfsdump(Filsys *fs) 1446 { 1447 long m, n, i; 1448 Off orba, rba, oroa, roa, sba, a; 1449 Timet tim; 1450 char tstr[20]; 1451 Iobuf *pr, *p1, *p; 1452 Dentry *dr, *d1, *d; 1453 Cache *h; 1454 Superb *s; 1455 Cw *cw; 1456 1457 if(fs->dev->type != Devcw) { 1458 print("cant dump; not cw device: %Z\n", fs->dev); 1459 return; 1460 } 1461 cw = fs->dev->private; 1462 if(cw == 0) { 1463 print("cant dump: has not been inited: %Z\n", fs->dev); 1464 return; 1465 } 1466 1467 tim = toytime(); 1468 wlock(&mainlock); /* dump */ 1469 1470 /* 1471 * set up static structure 1472 * with frequent variables 1473 */ 1474 cw->ndump = 0; 1475 cw->name[0] = 0; 1476 cw->depth = 0; 1477 1478 /* 1479 * cw root 1480 */ 1481 sync("before dump"); 1482 cw->fsize = cwsize(cw->dev); 1483 orba = cwraddr(cw->dev); 1484 print("cwroot %lld", (Wideoff)orba); 1485 cons.noage = 1; 1486 cw->all = cw->allflag; 1487 rba = cwrecur(cw, orba, Tsuper, 0, QPROOT); 1488 if(rba == 0) 1489 rba = orba; 1490 print("->%lld\n", (Wideoff)rba); 1491 sync("after cw"); 1492 1493 /* 1494 * partial super block 1495 */ 1496 p = getbuf(cw->dev, cwsaddr(cw->dev), Brd|Bmod|Bimm); 1497 s = (Superb*)p->iobuf; 1498 s->fsize = cw->fsize; 1499 s->cwraddr = rba; 1500 putbuf(p); 1501 1502 /* 1503 * partial cache block 1504 */ 1505 p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bimm|Bres); 1506 h = (Cache*)p->iobuf; 1507 h->fsize = cw->fsize; 1508 h->cwraddr = rba; 1509 putbuf(p); 1510 1511 /* 1512 * ro root 1513 */ 1514 oroa = cwraddr(cw->rodev); 1515 pr = getbuf(cw->dev, oroa, Brd|Bmod); 1516 dr = getdir(pr, 0); 1517 1518 datestr(tstr, time(nil)); /* tstr = "yyyymmdd" */ 1519 n = 0; 1520 for(a=0;; a++) { 1521 p1 = dnodebuf(pr, dr, a, Tdir, 0); 1522 if(!p1) 1523 goto bad; 1524 n++; 1525 for(i=0; i<DIRPERBUF; i++) { 1526 d1 = getdir(p1, i); 1527 if(!d1) 1528 goto bad; 1529 if(!(d1->mode & DALLOC)) 1530 goto found1; 1531 if(!memcmp(d1->name, tstr, 4)) 1532 goto found2; /* found entry */ 1533 } 1534 putbuf(p1); 1535 } 1536 1537 /* 1538 * no year directory, create one 1539 */ 1540 found1: 1541 p = getbuf(cw->dev, rba, Brd); 1542 d = getdir(p, 0); 1543 d1->qid = d->qid; 1544 d1->qid.version += n; 1545 memmove(d1->name, tstr, 4); 1546 d1->mode = d->mode; 1547 d1->uid = d->uid; 1548 d1->gid = d->gid; 1549 putbuf(p); 1550 accessdir(p1, d1, FWRITE, 0); 1551 1552 /* 1553 * put mmdd[count] in year directory 1554 */ 1555 found2: 1556 accessdir(p1, d1, FREAD, 0); 1557 putbuf(pr); 1558 pr = p1; 1559 dr = d1; 1560 1561 n = 0; 1562 m = 0; 1563 for(a=0;; a++) { 1564 p1 = dnodebuf(pr, dr, a, Tdir, 0); 1565 if(!p1) 1566 goto bad; 1567 n++; 1568 for(i=0; i<DIRPERBUF; i++) { 1569 d1 = getdir(p1, i); 1570 if(!d1) 1571 goto bad; 1572 if(!(d1->mode & DALLOC)) 1573 goto found; 1574 if(!memcmp(d1->name, tstr+4, 4)) 1575 m++; 1576 } 1577 putbuf(p1); 1578 } 1579 1580 /* 1581 * empty slot put in root 1582 */ 1583 found: 1584 if(m) /* how many dumps this date */ 1585 sprint(tstr+8, "%ld", m); 1586 1587 p = getbuf(cw->dev, rba, Brd); 1588 d = getdir(p, 0); 1589 *d1 = *d; /* qid is QPROOT */ 1590 putbuf(p); 1591 strcpy(d1->name, tstr+4); 1592 d1->qid.version += n; 1593 accessdir(p1, d1, FWRITE, 0); 1594 putbuf(p1); 1595 putbuf(pr); 1596 1597 cw->fsize = cwsize(cw->dev); 1598 oroa = cwraddr(cw->rodev); /* probably redundant */ 1599 print("roroot %lld", (Wideoff)oroa); 1600 1601 cons.noage = 0; 1602 cw->all = 0; 1603 roa = cwrecur(cw, oroa, Tsuper, 0, QPROOT); 1604 if(roa == 0) { 1605 print("[same]"); 1606 roa = oroa; 1607 } 1608 print("->%lld /%.4s/%s\n", (Wideoff)roa, tstr, tstr+4); 1609 sync("after ro"); 1610 1611 /* 1612 * final super block 1613 */ 1614 a = cwsaddr(cw->dev); 1615 print("sblock %lld", (Wideoff)a); 1616 p = getbuf(cw->dev, a, Brd|Bmod|Bimm); 1617 s = (Superb*)p->iobuf; 1618 s->last = a; 1619 sba = s->next; 1620 s->next = cw->fsize; 1621 cw->fsize++; 1622 s->fsize = cw->fsize; 1623 s->roraddr = roa; 1624 1625 cwio(cw->dev, sba, 0, Ogrow); 1626 cwio(cw->dev, sba, p->iobuf, Owrite); 1627 cwio(cw->dev, sba, 0, Odump); 1628 print("->%lld (->%lld)\n", (Wideoff)sba, (Wideoff)s->next); 1629 1630 putbuf(p); 1631 1632 /* 1633 * final cache block 1634 */ 1635 p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bimm|Bres); 1636 h = (Cache*)p->iobuf; 1637 h->fsize = cw->fsize; 1638 h->roraddr = roa; 1639 h->sbaddr = sba; 1640 putbuf(p); 1641 1642 rewalk(cw); 1643 sync("all done"); 1644 1645 print("%lld blocks queued for worm\n", (Wideoff)cw->ndump); 1646 print("%lld falsehits\n", (Wideoff)cw->falsehits); 1647 cw->nodump = 0; 1648 1649 /* 1650 * extend all of the locks 1651 */ 1652 tim = toytime() - tim; 1653 for(i=0; i<NTLOCK; i++) 1654 if(tlocks[i].time > 0) 1655 tlocks[i].time += tim; 1656 1657 wunlock(&mainlock); 1658 nextdump(time(nil)); 1659 return; 1660 1661 bad: 1662 panic("dump: bad"); 1663 } 1664 1665 void 1666 mvstates(Device *dev, int s1, int s2, int side) 1667 { 1668 Iobuf *p, *cb; 1669 Cache *h; 1670 Bucket *b; 1671 Centry *c, *ce; 1672 Off m, lo, hi, msize, maddr; 1673 Cw *cw; 1674 1675 cw = dev->private; 1676 lo = 0; 1677 hi = lo + devsize(dev->cw.w); /* size of all sides totalled */ 1678 if(side >= 0) { 1679 /* operate on only a single disc side */ 1680 Sidestarts ss; 1681 1682 wormsidestarts(dev, side, &ss); 1683 lo = ss.sstart; 1684 hi = ss.s1start; 1685 } 1686 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres); 1687 if(!cb || checktag(cb, Tcache, QPSUPER)) 1688 panic("cwstats: checktag c bucket"); 1689 h = (Cache*)cb->iobuf; 1690 msize = h->msize; 1691 maddr = h->maddr; 1692 putbuf(cb); 1693 1694 for(m=0; m<msize; m++) { 1695 p = getbuf(cw->cdev, maddr + m/BKPERBLK, Brd|Bmod); 1696 if(!p || checktag(p, Tbuck, maddr + m/BKPERBLK)) 1697 panic("cwtest: checktag c bucket"); 1698 b = (Bucket*)p->iobuf + m%BKPERBLK; 1699 ce = b->entry + CEPERBK; 1700 for(c=b->entry; c<ce; c++) 1701 if(c->state == s1 && c->waddr >= lo && c->waddr < hi) 1702 c->state = s2; 1703 putbuf(p); 1704 } 1705 } 1706 1707 void 1708 prchain(Device *dev, Off m, int flg) 1709 { 1710 Iobuf *p; 1711 Superb *s; 1712 1713 if(m == 0) { 1714 if(flg) 1715 m = cwsaddr(dev); 1716 else 1717 m = getstartsb(dev); 1718 } 1719 p = getbuf(devnone, Cwxx2, 0); 1720 s = (Superb*)p->iobuf; 1721 for(;;) { 1722 memset(p->iobuf, 0, RBUFSIZE); 1723 if(devread(WDEV(dev), m, p->iobuf) || 1724 checktag(p, Tsuper, QPSUPER)) 1725 break; 1726 if(flg) { 1727 print("dump %lld is good; %lld prev\n", (Wideoff)m, 1728 (Wideoff)s->last); 1729 print("\t%lld cwroot; %lld roroot\n", 1730 (Wideoff)s->cwraddr, (Wideoff)s->roraddr); 1731 if(m <= s->last) 1732 break; 1733 m = s->last; 1734 } else { 1735 print("dump %lld is good; %lld next\n", (Wideoff)m, 1736 (Wideoff)s->next); 1737 print("\t%lld cwroot; %lld roroot\n", 1738 (Wideoff)s->cwraddr, (Wideoff)s->roraddr); 1739 if(m >= s->next) 1740 break; 1741 m = s->next; 1742 } 1743 } 1744 putbuf(p); 1745 } 1746 1747 void 1748 touchsb(Device *dev) 1749 { 1750 Iobuf *p; 1751 Off m; 1752 1753 m = cwsaddr(dev); 1754 p = getbuf(devnone, Cwxx2, 0); 1755 1756 memset(p->iobuf, 0, RBUFSIZE); 1757 if(devread(WDEV(dev), m, p->iobuf) || 1758 checktag(p, Tsuper, QPSUPER)) 1759 print("%Z block %lld WORM SUPER BLOCK READ FAILED\n", 1760 WDEV(dev), (Wideoff)m); 1761 else 1762 print("%Z touch superblock %lld\n", WDEV(dev), (Wideoff)m); 1763 putbuf(p); 1764 } 1765 1766 void 1767 storesb(Device *dev, Off last, int doit) 1768 { 1769 Iobuf *ph, *ps; 1770 Cache *h; 1771 Superb *s; 1772 Off sbaddr, qidgen; 1773 1774 sbaddr = cwsaddr(dev); 1775 1776 ps = getbuf(devnone, Cwxx2, 0); 1777 if(!ps) { 1778 print("sbstore: getbuf\n"); 1779 return; 1780 } 1781 1782 /* 1783 * try to read last sb 1784 */ 1785 memset(ps->iobuf, 0, RBUFSIZE); 1786 if(devread(WDEV(dev), last, ps->iobuf) || 1787 checktag(ps, Tsuper, QPSUPER)) 1788 print("read last failed\n"); 1789 else 1790 print("read last succeeded\n"); 1791 1792 s = (Superb*)ps->iobuf; 1793 qidgen = s->qidgen; 1794 if(qidgen == 0) 1795 qidgen = 0x31415; 1796 qidgen += 1000; 1797 if(s->next != sbaddr) 1798 print("next(last) is not sbaddr %lld %lld\n", 1799 (Wideoff)s->next, (Wideoff)sbaddr); 1800 else 1801 print("next(last) is sbaddr\n"); 1802 1803 /* 1804 * read cached superblock 1805 */ 1806 ph = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); 1807 if(!ph || checktag(ph, Tcache, QPSUPER)) { 1808 print("cwstats: checktag c bucket\n"); 1809 if(ph) 1810 putbuf(ph); 1811 putbuf(ps); 1812 return; 1813 } else 1814 print("read cached sb succeeded\n"); 1815 1816 h = (Cache*)ph->iobuf; 1817 1818 memset(ps->iobuf, 0, RBUFSIZE); 1819 settag(ps, Tsuper, QPSUPER); 1820 ps->flags = 0; 1821 s = (Superb*)ps->iobuf; 1822 1823 s->cwraddr = h->cwraddr; 1824 s->roraddr = h->roraddr; 1825 s->fsize = h->fsize; 1826 s->fstart = 2; 1827 s->last = last; 1828 s->next = h->roraddr+1; 1829 1830 s->qidgen = qidgen; 1831 putbuf(ph); 1832 1833 if(s->fsize-1 != s->next || 1834 s->fsize-2 != s->roraddr || 1835 s->fsize-5 != s->cwraddr) { 1836 print("addrs not in relationship %lld %lld %lld %lld\n", 1837 (Wideoff)s->cwraddr, (Wideoff)s->roraddr, 1838 (Wideoff)s->next, (Wideoff)s->fsize); 1839 putbuf(ps); 1840 return; 1841 } else 1842 print("addresses in relation\n"); 1843 1844 if(doit) 1845 if(devwrite(WDEV(dev), sbaddr, ps->iobuf)) 1846 print("%Z block %lld WORM SUPER BLOCK WRITE FAILED\n", 1847 WDEV(dev), (Wideoff)sbaddr); 1848 ps->flags = 0; 1849 putbuf(ps); 1850 } 1851 1852 void 1853 savecache(Device *dev) 1854 { 1855 Iobuf *p, *cb; 1856 Cache *h; 1857 Bucket *b; 1858 Centry *c, *ce; 1859 long n, left; 1860 Off m, maddr, msize, *longp, nbyte; 1861 Device *cdev; 1862 1863 if(walkto("/adm/cache") || con_open(FID2, OWRITE|OTRUNC)) { 1864 print("cant open /adm/cache\n"); 1865 return; 1866 } 1867 cdev = CDEV(dev); 1868 cb = getbuf(cdev, CACHE_ADDR, Brd|Bres); 1869 if(!cb || checktag(cb, Tcache, QPSUPER)) 1870 panic("savecache: checktag c bucket"); 1871 h = (Cache*)cb->iobuf; 1872 msize = h->msize; 1873 maddr = h->maddr; 1874 putbuf(cb); 1875 1876 n = BUFSIZE; /* calculate write size */ 1877 if(n > MAXDAT) 1878 n = MAXDAT; 1879 1880 cb = getbuf(devnone, Cwxx4, 0); 1881 longp = (Off *)cb->iobuf; 1882 left = n/sizeof(Off); 1883 cons.offset = 0; 1884 1885 for(m=0; m<msize; m++) { 1886 if(left < BKPERBLK) { 1887 nbyte = (n/sizeof(Off) - left) * sizeof(Off); 1888 con_write(FID2, cb->iobuf, cons.offset, nbyte); 1889 cons.offset += nbyte; 1890 longp = (Off *)cb->iobuf; 1891 left = n/sizeof(Off); 1892 } 1893 p = getbuf(cdev, maddr + m/BKPERBLK, Brd); 1894 if(!p || checktag(p, Tbuck, maddr + m/BKPERBLK)) 1895 panic("cwtest: checktag c bucket"); 1896 b = (Bucket*)p->iobuf + m%BKPERBLK; 1897 ce = b->entry + CEPERBK; 1898 for(c = b->entry; c < ce; c++) 1899 if(c->state == Cread) { 1900 *longp++ = c->waddr; 1901 left--; 1902 } 1903 putbuf(p); 1904 } 1905 nbyte = (n/sizeof(Off) - left) * sizeof(Off); 1906 con_write(FID2, cb->iobuf, cons.offset, nbyte); 1907 putbuf(cb); 1908 } 1909 1910 void 1911 loadcache(Device *dev, int dskno) 1912 { 1913 Iobuf *p, *cb; 1914 Off m, nbyte, *longp, count; 1915 Sidestarts ss; 1916 1917 if(walkto("/adm/cache") || con_open(FID2, OREAD)) { 1918 print("cant open /adm/cache\n"); 1919 return; 1920 } 1921 1922 cb = getbuf(devnone, Cwxx4, 0); 1923 cons.offset = 0; 1924 count = 0; 1925 1926 if (dskno >= 0) 1927 wormsidestarts(dev, dskno, &ss); 1928 for(;;) { 1929 memset(cb->iobuf, 0, BUFSIZE); 1930 nbyte = con_read(FID2, cb->iobuf, cons.offset, 100) / sizeof(Off); 1931 if(nbyte <= 0) 1932 break; 1933 cons.offset += nbyte * sizeof(Off); 1934 longp = (Off *)cb->iobuf; 1935 while(nbyte > 0) { 1936 m = *longp++; 1937 nbyte--; 1938 if(m == 0) 1939 continue; 1940 /* if given a diskno, restrict to just that disc side */ 1941 if(dskno < 0 || m >= ss.sstart && m < ss.s1start) { 1942 p = getbuf(dev, m, Brd); 1943 if(p) 1944 putbuf(p); 1945 count++; 1946 } 1947 } 1948 } 1949 putbuf(cb); 1950 print("%lld blocks loaded from worm %d\n", (Wideoff)count, dskno); 1951 } 1952 1953 void 1954 morecache(Device *dev, int dskno, Off size) 1955 { 1956 Iobuf *p; 1957 Off m, ml, mh, mm, count; 1958 Cache *h; 1959 Sidestarts ss; 1960 1961 p = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres); 1962 if(!p || checktag(p, Tcache, QPSUPER)) 1963 panic("savecache: checktag c bucket"); 1964 h = (Cache*)p->iobuf; 1965 mm = h->wmax; 1966 putbuf(p); 1967 1968 wormsidestarts(dev, dskno, &ss); 1969 ml = ss.sstart; /* start at beginning of disc side #dskno */ 1970 mh = ml + size; 1971 if(mh > mm) { 1972 mh = mm; 1973 print("limited to %lld\n", (Wideoff)mh-ml); 1974 } 1975 1976 count = 0; 1977 for(m=ml; m < mh; m++) { 1978 p = getbuf(dev, m, Brd); 1979 if(p) 1980 putbuf(p); 1981 count++; 1982 } 1983 print("%lld blocks loaded from worm %d\n", (Wideoff)count, dskno); 1984 } 1985 1986 void 1987 blockcmp(Device *dev, Off wa, Off ca) 1988 { 1989 Iobuf *p1, *p2; 1990 int i, c; 1991 1992 p1 = getbuf(WDEV(dev), wa, Brd); 1993 if(!p1) { 1994 print("blockcmp: wdev error\n"); 1995 return; 1996 } 1997 1998 p2 = getbuf(CDEV(dev), ca, Brd); 1999 if(!p2) { 2000 print("blockcmp: cdev error\n"); 2001 putbuf(p1); 2002 return; 2003 } 2004 2005 c = 0; 2006 for(i=0; i<RBUFSIZE; i++) 2007 if(p1->iobuf[i] != p2->iobuf[i]) { 2008 print("%4d: %.2x %.2x\n", 2009 i, 2010 p1->iobuf[i]&0xff, 2011 p2->iobuf[i]&0xff); 2012 c++; 2013 if(c >= 10) 2014 break; 2015 } 2016 2017 if(c == 0) 2018 print("no error\n"); 2019 putbuf(p1); 2020 putbuf(p2); 2021 } 2022 2023 void 2024 wblock(Device *dev, Off addr) 2025 { 2026 Iobuf *p1; 2027 int i; 2028 2029 p1 = getbuf(dev, addr, Brd); 2030 if(p1) { 2031 i = devwrite(WDEV(dev), addr, p1->iobuf); 2032 print("i = %d\n", i); 2033 putbuf(p1); 2034 } 2035 } 2036 2037 void 2038 cwtest(Device*) 2039 { 2040 } 2041 2042 #ifdef XXX 2043 /* garbage to change sb size 2044 * probably will need it someday 2045 */ 2046 fsz = number(0, 0, 10); 2047 count = 0; 2048 if(fsz == number(0, -1, 10)) 2049 count = -1; /* really do it */ 2050 print("fsize = %ld\n", fsz); 2051 cdev = CDEV(dev); 2052 cb = getbuf(cdev, CACHE_ADDR, Brd|Bres); 2053 if(!cb || checktag(cb, Tcache, QPSUPER)) 2054 panic("cwstats: checktag c bucket"); 2055 h = (Cache*)cb->iobuf; 2056 for(m=0; m<h->msize; m++) { 2057 p = getbuf(cdev, h->maddr + m/BKPERBLK, Brd|Bmod); 2058 if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK)) 2059 panic("cwtest: checktag c bucket"); 2060 b = (Bucket*)p->iobuf + m%BKPERBLK; 2061 ce = b->entry + CEPERBK; 2062 for(c=b->entry; c<ce; c++) { 2063 if(c->waddr < fsz) 2064 continue; 2065 if(count < 0) { 2066 c->state = Cnone; 2067 continue; 2068 } 2069 if(c->state != Cdirty) 2070 count++; 2071 } 2072 putbuf(p); 2073 } 2074 if(count < 0) { 2075 print("old cache hsize = %ld\n", h->fsize); 2076 h->fsize = fsz; 2077 cb->flags |= Bmod; 2078 p = getbuf(dev, h->sbaddr, Brd|Bmod); 2079 s = (Superb*)p->iobuf; 2080 print("old super hsize = %ld\n", s->fsize); 2081 s->fsize = fsz; 2082 putbuf(p); 2083 } 2084 putbuf(cb); 2085 print("count = %lld\n", (Wideoff)count); 2086 #endif 2087 2088 int 2089 convstate(char *name) 2090 { 2091 int i; 2092 2093 for(i=0; i<nelem(cwnames); i++) 2094 if(cwnames[i]) 2095 if(strcmp(cwnames[i], name) == 0) 2096 return i; 2097 return -1; 2098 } 2099 2100 void 2101 searchtag(Device *d, Off a, int tag, int n) 2102 { 2103 Iobuf *p; 2104 Tag *t; 2105 int i; 2106 2107 if(a == 0) 2108 a = getstartsb(d); 2109 p = getbuf(devnone, Cwxx2, 0); 2110 t = (Tag*)(p->iobuf+BUFSIZE); 2111 for(i=0; i<n; i++) { 2112 memset(p->iobuf, 0, RBUFSIZE); 2113 if(devread(WDEV(d), a+i, p->iobuf)) { 2114 if(n == 1000) 2115 break; 2116 continue; 2117 } 2118 if(t->tag == tag) { 2119 print("tag %d found at %Z %lld\n", tag, d, (Wideoff)a+i); 2120 break; 2121 } 2122 } 2123 putbuf(p); 2124 } 2125 2126 void 2127 cmd_cwcmd(int argc, char *argv[]) 2128 { 2129 Device *dev; 2130 char *arg; 2131 char str[28]; 2132 Off s1, s2, a, b, n; 2133 Cw *cw; 2134 2135 if(argc <= 1) { 2136 print("\tcwcmd mvstate state1 state2 [platter]\n"); 2137 print("\tcwcmd prchain [start] [bakflg]\n"); 2138 print("\tcwcmd searchtag [start] [tag] [blocks]\n"); 2139 print("\tcwcmd touchsb\n"); 2140 print("\tcwcmd savecache\n"); 2141 print("\tcwcmd loadcache [dskno]\n"); 2142 print("\tcwcmd morecache dskno [count]\n"); 2143 print("\tcwcmd blockcmp wbno cbno\n"); 2144 print("\tcwcmd startdump [01]\n"); 2145 print("\tcwcmd acct\n"); 2146 print("\tcwcmd clearacct\n"); 2147 return; 2148 } 2149 arg = argv[1]; 2150 2151 /* 2152 * items not depend on a cw filesystem 2153 */ 2154 if(strcmp(arg, "acct") == 0) { 2155 for(a=0; a<nelem(growacct); a++) { 2156 b = growacct[a]; 2157 if(b) { 2158 uidtostr(str, a, 1); 2159 print("%10lld %s\n", 2160 ((Wideoff)b*ADDFREE*RBUFSIZE+500000)/1000000, 2161 str); 2162 } 2163 } 2164 return; 2165 } 2166 if(strcmp(arg, "clearacct") == 0) { 2167 memset(growacct, 0, sizeof(growacct)); 2168 return; 2169 } 2170 2171 /* 2172 * items depend on cw filesystem 2173 */ 2174 dev = cons.curfs->dev; 2175 if(dev == 0 || dev->type != Devcw || dev->private == 0) { 2176 print("cfs not a cw filesystem: %Z\n", dev); 2177 return; 2178 } 2179 cw = dev->private; 2180 if(strcmp(arg, "searchtag") == 0) { 2181 a = 0; 2182 if(argc > 2) 2183 a = number(argv[2], 0, 10); 2184 b = Tsuper; 2185 if(argc > 3) 2186 b = number(argv[3], 0, 10); 2187 n = 1000; 2188 if(argc > 4) 2189 n = number(argv[4], 0, 10); 2190 searchtag(dev, a, b, n); 2191 } else if(strcmp(arg, "mvstate") == 0) { 2192 if(argc < 4) 2193 goto bad; 2194 s1 = convstate(argv[2]); 2195 s2 = convstate(argv[3]); 2196 if(s1 < 0 || s2 < 0) 2197 goto bad; 2198 a = -1; 2199 if(argc > 4) 2200 a = number(argv[4], 0, 10); 2201 mvstates(dev, s1, s2, a); 2202 return; 2203 bad: 2204 print("cwcmd mvstate: bad args\n"); 2205 } else if(strcmp(arg, "prchain") == 0) { 2206 a = 0; 2207 if(argc > 2) 2208 a = number(argv[2], 0, 10); 2209 s1 = 0; 2210 if(argc > 3) 2211 s1 = number(argv[3], 0, 10); 2212 prchain(dev, a, s1); 2213 } else if(strcmp(arg, "touchsb") == 0) 2214 touchsb(dev); 2215 else if(strcmp(arg, "savecache") == 0) 2216 savecache(dev); 2217 else if(strcmp(arg, "loadcache") == 0) { 2218 s1 = -1; 2219 if(argc > 2) 2220 s1 = number(argv[2], 0, 10); 2221 loadcache(dev, s1); 2222 } else if(strcmp(arg, "morecache") == 0) { 2223 if(argc <= 2) { 2224 print("arg count\n"); 2225 return; 2226 } 2227 s1 = number(argv[2], 0, 10); 2228 if(argc > 3) 2229 s2 = number(argv[3], 0, 10); 2230 else 2231 s2 = wormsizeside(dev, s1); /* default to 1 disc side */ 2232 morecache(dev, s1, s2); 2233 } else if(strcmp(arg, "blockcmp") == 0) { 2234 if(argc < 4) { 2235 print("cannot arg count\n"); 2236 return; 2237 } 2238 s1 = number(argv[2], 0, 10); 2239 s2 = number(argv[3], 0, 10); 2240 blockcmp(dev, s1, s2); 2241 } else if(strcmp(arg, "startdump") == 0) { 2242 if(argc > 2) 2243 cw->nodump = number(argv[2], 0, 10); 2244 cw->nodump = !cw->nodump; 2245 if(cw->nodump) 2246 print("dump stopped\n"); 2247 else 2248 print("dump allowed\n"); 2249 } else if(strcmp(arg, "allflag") == 0) { 2250 if(argc > 2) 2251 cw->allflag = number(argv[2], 0, 10); 2252 else 2253 cw->allflag = !cw->allflag; 2254 print("allflag = %d; falsehits = %lld\n", 2255 cw->allflag, (Wideoff)cw->falsehits); 2256 } else if(strcmp(arg, "storesb") == 0) { 2257 a = 4168344; 2258 b = 0; 2259 if(argc > 2) 2260 a = number(argv[2], 4168344, 10); 2261 if(argc > 3) 2262 b = number(argv[3], 0, 10); 2263 storesb(dev, a, b); 2264 } else if(strcmp(arg, "test") == 0) 2265 cwtest(dev); 2266 else 2267 print("unknown cwcmd %s\n", arg); 2268 } 2269