6 #define CDEV(d) ((d)->cw.c)
7 #define WDEV(d) ((d)->cw.w)
8 #define RDEV(d) ((d)->cw.ro)
14 CACHE_ADDR = SUPER_ADDR,
21 /* states -- beware these are recorded on the cache */
28 Cdump1, /* inactive form of dump */
31 /* opcodes -- these are not recorded */
50 int dbucket; /* last bucket dumped */
51 Off daddr; /* last block dumped */
55 * following are cached variables for dumps
60 int all; /* local flag to recur on modified dirs */
61 int allflag; /* global flag to recur on modified dirs */
62 Off falsehits; /* times recur found modified blocks */
65 char namepad[NAMELEN+10];
69 static char* cwnames[] =
87 Centry* getcentry(Bucket*, Off);
88 int cwio(Device*, Off, void*, int);
89 void cmd_cwcmd(int, char*[]);
96 cmd_dump(int argc, char *argv[])
104 print("%s: unknown file system\n", argv[1]);
115 cmd_statw(int, char*[])
123 Off m, nw, bw, state[Onone];
124 Off sbfsize, sbcwraddr, sbroraddr, sblast, sbnext;
125 Off hmsize, hmaddr, dsize, dsizepct;
132 if(dev->type != Devcw) {
133 print("curfs not type cw\n");
139 print("curfs not inited\n");
143 print("cwstats %s\n", fs->name);
151 print("\tfilesys %s\n", fs->name);
152 // print("\tnio =%7W%7W%7W\n", cw->ncwio+0, cw->ncwio+1, cw->ncwio+2);
153 p = getbuf(dev, cwsaddr(dev), Brd);
154 if(!p || checktag(p, Tsuper, QPSUPER)) {
155 print("cwstats: checktag super\n");
162 sb = (Superb*)p->iobuf;
164 sbcwraddr = sb->cwraddr;
165 sbroraddr = sb->roraddr;
171 p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
172 if(!p || checktag(p, Tcache, QPSUPER)) {
173 print("cwstats: checktag c bucket\n");
178 h = (Cache*)p->iobuf;
182 print("\t\tmaddr = %8lld\n", (Wideoff)hmaddr);
183 print("\t\tmsize = %8lld\n", (Wideoff)hmsize);
184 print("\t\tcaddr = %8lld\n", (Wideoff)h->caddr);
185 print("\t\tcsize = %8lld\n", (Wideoff)h->csize);
186 print("\t\tsbaddr = %8lld\n", (Wideoff)h->sbaddr);
187 print("\t\tcraddr = %8lld %8lld\n",
188 (Wideoff)h->cwraddr, (Wideoff)sbcwraddr);
189 print("\t\troaddr = %8lld %8lld\n",
190 (Wideoff)h->roraddr, (Wideoff)sbroraddr);
191 /* print stats in terms of (first-)disc sides */
192 dsize = wormsizeside(dev, 0);
194 dsize = h->wsize; /* it's probably a fake worm */
196 dsize = 1000; /* don't divide by zero */
198 dsizepct = dsize/100;
199 print("\t\tfsize = %8lld %8lld %2lld+%2lld%%\n", (Wideoff)h->fsize,
200 (Wideoff)sbfsize, (Wideoff)h->fsize/dsize,
201 (Wideoff)(h->fsize%dsize)/dsizepct);
202 print("\t\tslast = %8lld\n", (Wideoff)sblast);
203 print("\t\tsnext = %8lld\n", (Wideoff)sbnext);
204 print("\t\twmax = %8lld %2lld+%2lld%%\n",
205 (Wideoff)h->wmax, (Wideoff)h->wmax/dsize,
206 (Wideoff)(h->wmax%dsize)/dsizepct);
207 print("\t\twsize = %8lld %2lld+%2lld%%\n",
208 (Wideoff)h->wsize, (Wideoff)h->wsize/dsize,
209 (Wideoff)(h->wsize%dsize)/dsizepct);
212 bw = 0; /* max filled bucket */
213 memset(state, 0, sizeof(state));
214 for(m = 0; m < hmsize; m++) {
215 p = getbuf(cw->cdev, hmaddr + m/BKPERBLK, Brd);
216 if(!p || checktag(p, Tbuck, hmaddr + m/BKPERBLK)) {
217 print("cwstats: checktag c bucket\n");
222 b = (Bucket*)p->iobuf + m%BKPERBLK;
223 ce = b->entry + CEPERBK;
225 for(c = b->entry; c < ce; c++) {
228 if(s != Cnone && s != Cread)
235 for(s = Cnone; s < Cerror; s++)
236 print("\t\t%6lld %s\n", (Wideoff)state[s], cwnames[s]);
237 print("\t\tcache %2lld%% full\n", ((Wideoff)bw*100)/CEPERBK);
241 dumpblock(Device *dev)
243 Iobuf *p, *cb, *p1, *p2;
247 Off m, a, msize, maddr, wmax, caddr;
252 if(cw == 0 || cw->nodump)
255 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
256 h = (Cache*)cb->iobuf;
263 for(m=msize; m>=0; m--) {
265 if(a < 0 || a >= msize)
268 p = getbuf(cw->cdev, maddr + a/BKPERBLK, Brd);
269 b = (Bucket*)p->iobuf + a%BKPERBLK;
270 ce = b->entry + CEPERBK;
272 for(c = b->entry; c < ce; c++)
273 if(c->state == Cdump) {
278 if(c->waddr < cw->daddr) {
279 if(bc->waddr < cw->daddr &&
280 bc->waddr > c->waddr)
284 if(bc->waddr < cw->daddr ||
285 bc->waddr > c->waddr)
296 print("%lld blocks copied to worm\n", (Wideoff)cw->ncopy);
304 a += (c - b->entry)*msize + caddr;
306 a = a*CEPERBK + (c - b->entry) + caddr;
307 p1 = getbuf(devnone, Cwdump1, 0);
312 if(count > 10 || devread(cw->cdev, a, p1->iobuf))
316 s1 = devwrite(cw->wdev, m, p1->iobuf);
318 p2 = getbuf(devnone, Cwdump2, 0);
319 s2 = devread(cw->wdev, m, p2->iobuf);
321 if(s1 == 0x61 && s2 == 0x60) {
327 if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE))
334 if(conf.dumpreread) {
335 p2 = getbuf(devnone, Cwdump2, 0);
336 s1 = devread(cw->wdev, m, p2->iobuf);
339 if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) {
340 fprint(2, "reread C%lld W%lld didnt compare\n",
341 (Wideoff)a, (Wideoff)m);
353 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres);
354 h = (Cache*)cb->iobuf;
373 print("stopping dump!!\n");
389 cmd_install("dump", "-- make dump backup to worm", cmd_dump);
390 cmd_install("statw", "-- cache/worm stats", cmd_statw);
391 cmd_install("cwcmd", "subcommand -- cache/worm errata", cmd_cwcmd);
392 roflag = flag_install("ro", "-- ro reads and writes");
395 cw = malloc(sizeof(Cw));
401 cw->cdev = CDEV(dev);
402 cw->wdev = WDEV(dev);
403 cw->rodev = RDEV(dev);
420 l = devsize(cw->wdev);
421 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres);
422 h = (Cache*)cb->iobuf;
423 h->toytime = toytime() + SECOND(30);
428 print("wdev changed size %lld to %lld\n",
429 (Wideoff)m, (Wideoff)l);
434 for(m=0; m<h->msize; m++) {
435 p = getbuf(cw->cdev, h->maddr + m/BKPERBLK, Brd);
436 if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK))
437 panic("cwinit: checktag c bucket");
449 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
450 sa = ((Cache*)cb->iobuf)->sbaddr;
463 fprint(2, "unknown dev in cwraddr %Z\n", dev);
467 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
468 ra = ((Cache*)cb->iobuf)->cwraddr;
472 cb = getbuf(CDEV(dev->ro.parent), CACHE_ADDR, Brd|Bres);
473 ra = ((Cache*)cb->iobuf)->roraddr;
486 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
487 fs = ((Cache*)cb->iobuf)->fsize;
493 cwread(Device *dev, Off b, void *c)
495 return cwio(dev, b, c, Oread) == Cerror;
499 cwwrite(Device *dev, Off b, void *c)
501 return cwio(dev, b, c, Owrite) == Cerror;
505 roread(Device *dev, Off b, void *c)
511 * maybe better is to try buffer pool first
514 if(d == 0 || d->type != Devcw ||
515 d->private == 0 || RDEV(d) != dev) {
516 fprint(2, "bad rodev %Z\n", dev);
519 s = cwio(d, b, 0, Onone);
520 if(s == Cdump || s == Cdump1 || s == Cread) {
521 s = cwio(d, b, c, Oread);
522 if(s == Cdump || s == Cdump1 || s == Cread) {
523 if(cons.flags & roflag)
524 print("roread: %Z %lld -> %Z(hit)\n",
529 if(cons.flags & roflag)
530 print("roread: %Z %lld -> %Z(miss)\n",
531 dev, (Wideoff)b, WDEV(d));
532 return devread(WDEV(d), b, c);
536 cwio(Device *dev, Off addr, void *buf, int opcode)
538 Iobuf *p, *p1, *p2, *cb;
542 Off bn, a1, a2, max, newmax;
548 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
549 h = (Cache*)cb->iobuf;
550 if(toytime() >= h->toytime) {
552 h->toytime = toytime() + SECOND(30);
561 bn = addr % h->msize;
562 a1 = h->maddr + bn/BKPERBLK;
566 a2 = bn*CEPERBK + h->caddr;
572 p = getbuf(cw->cdev, a1, Brd|Bmod);
573 if(!p || checktag(p, Tbuck, a1))
574 panic("cwio: checktag c bucket");
575 b = (Bucket*)p->iobuf + bn%BKPERBLK;
577 c = getcentry(b, addr);
580 fprint(2, "%Z disk cache bucket %lld is full\n",
581 cw->cdev, (Wideoff)a1);
585 a2 += (c - b->entry) * h->msize;
603 if(!devread(cw->cdev, a2, buf))
608 if(devread(cw->wdev, addr, buf)) {
614 if(!devwrite(cw->cdev, a2, buf))
622 if(devread(cw->cdev, a2, buf))
636 * this is hard part -- a dump block must be
637 * sent to the worm if it is rewritten.
638 * if this causes an error, there is no
639 * place to save the dump1 data. the block
640 * is just reclassified as 'dump1' (botch)
642 p1 = getbuf(devnone, Cwio1, 0);
643 if(devread(cw->cdev, a2, p1->iobuf)) {
645 fprint(2, "cwio: write induced dump error - r cache\n");
648 if(devwrite(cw->cdev, a2, buf)) {
655 if(devwrite(cw->wdev, addr, p1->iobuf)) {
656 p2 = getbuf(devnone, Cwio2, 0);
657 if(devread(cw->wdev, addr, p2->iobuf)) {
660 fprint(2, "cwio: write induced dump error - r+w worm\n");
663 if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) {
666 fprint(2, "cwio: write induced dump error - w worm\n");
679 if(devwrite(cw->cdev, a2, buf)) {
688 if(devwrite(cw->cdev, a2, buf))
696 fprint(2, "%Z for block %lld cwgrow with state = %s\n",
697 cw->cdev, (Wideoff)addr, cwnames[state]);
704 if(state != Cdirty) { /* BOTCH */
705 fprint(2, "%Z for block %lld cwdump with state = %s\n",
706 cw->cdev, (Wideoff)addr, cwnames[state]);
710 cw->ndump++; /* only called from dump command */
714 if(state != Cwrite) {
716 fprint(2, "%Z for block %lld cwrele with state = %s\n",
717 cw->cdev, (Wideoff)addr, cwnames[state]);
724 if(state == Cwrite || state == Cread)
729 print("cwio: %Z %lld s=%s o=%s ns=%s\n",
730 dev, (Wideoff)addr, cwnames[state],
735 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres);
736 h = (Cache*)cb->iobuf;
744 fprint(2, "%Z block %lld cw state = %s; cw opcode = %s",
745 dev, (Wideoff)addr, cwnames[state], cwnames[opcode]);
751 cwgrow(Device *dev, Superb *sb, int)
757 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bmod|Bres);
758 h = (Cache*)cb->iobuf;
770 for(nfs--; nfs>=fs; nfs--)
771 switch(cwio(dev, nfs, 0, Ogrow)) {
775 addfree(dev, nfs, sb);
781 cwfree(Device *dev, Off addr)
785 if(dev->type == Devcw) {
786 state = cwio(dev, addr, 0, Ofree);
788 return 1; /* do not put in freelist */
790 return 0; /* put in freelist */
797 Centry *c, *c1, *c2, *ce;
801 if(b->agegen < CEPERBK || b->agegen > MAXAGE) {
802 print("agegen %ld\n", b->agegen);
806 ce = b->entry + CEPERBK;
807 c1 = 0; /* lowest age last pass */
809 c2 = 0; /* lowest age this pass */
810 for(c = b->entry; c < ce; c++) {
811 if(c1 != 0 && c != c1) {
812 if(c->age == c1->age) {
813 print("same age %d\n", c->age);
816 if(c1->waddr == c->waddr)
817 if(c1->state != Cnone)
818 if(c->state != Cnone) {
819 print("same waddr %lld\n",
824 if(c1 != 0 && c->age <= c1->age)
826 if(c2 == 0 || c->age < c2->age)
832 if(c1->age >= b->agegen) {
833 print("age >= generator %d %ld\n", c1->age, b->agegen);
842 resequence(Bucket *b)
847 ce = b->entry + CEPERBK;
848 for(c = b->entry; c < ce; c++) {
853 b->agegen += CEPERBK;
858 for(c = b->entry; c < ce; c++) {
861 if(cr == 0 || c->age < age) {
875 getcentry(Bucket *b, Off addr)
881 * search for cache hit
882 * find oldest block as byproduct
884 ce = b->entry + CEPERBK;
887 for(c = b->entry; c < ce; c++) {
897 if(cr == 0 || c->age < age) {
908 return 0; /* bucket is full */
915 * update the age to get filo cache.
916 * small number in age means old
918 if(!cons.noage || c->state == Cnone) {
923 if(age < 0 || age >= MAXAGE)
931 * calculate new buckets
934 cacheinit(Device *dev)
942 print("cache init %Z\n", dev);
946 cb = getbuf(cdev, CACHE_ADDR, Bmod|Bres);
947 memset(cb->iobuf, 0, RBUFSIZE);
948 settag(cb, Tcache, QPSUPER);
949 h = (Cache*)cb->iobuf;
952 * calculate csize such that
953 * tsize = msize/BKPERBLK + csize and
954 * msize = csize/CEPERBK
956 h->maddr = CACHE_ADDR + 1;
957 m = devsize(cdev) - h->maddr;
958 h->csize = ((Devsize)(m-1) * CEPERBK*BKPERBLK) / (CEPERBK*BKPERBLK+1);
959 h->msize = h->csize/CEPERBK - 5;
960 while(!prime(h->msize))
962 h->csize = h->msize*CEPERBK;
963 h->caddr = h->maddr + (h->msize+BKPERBLK-1)/BKPERBLK;
964 h->wsize = devsize(WDEV(dev));
967 panic("cache too small");
968 if(h->caddr + h->csize > m)
969 panic("cache size error");
974 for(m=h->maddr; m<h->caddr; m++) {
975 p = getbuf(cdev, m, Bmod);
976 memset(p->iobuf, 0, RBUFSIZE);
984 getstartsb(Device *dev)
989 for(f=filsys; f->name; f++){
990 if(devcmpr(f->dev, dev) == 0) {
991 for(s=startsb; s->name; s++)
992 if(strcmp(f->name, s->name) == 0)
994 fprint(2, "getstartsb: no special starting superblock for %Z %s\n",
999 fprint(2, "getstartsb: no filsys for device %Z\n", dev);
1005 * calculate new buckets
1006 * get superblock from
1007 * last worm dump block.
1010 cwrecover(Device *dev)
1019 print("cwrecover %Z\n", dev);
1023 p = getbuf(devnone, Cwxx1, 0);
1024 s = (Superb*)p->iobuf;
1026 m = getstartsb(dev);
1031 memset(p->iobuf, 0, RBUFSIZE);
1032 if(devread(wdev, m, p->iobuf) ||
1033 checktag(p, Tsuper, QPSUPER))
1038 print("dump %lld is good; %lld next\n", (Wideoff)baddr, (Wideoff)m);
1039 if(baddr == conf.recovsb)
1044 panic("recover: no superblock");
1046 p = getbuf(wdev, baddr, Brd);
1047 s = (Superb*)p->iobuf;
1049 cb = cacheinit(dev);
1050 h = (Cache*)cb->iobuf;
1052 h->cwraddr = s->cwraddr;
1053 h->roraddr = s->roraddr;
1054 h->fsize = s->fsize + 100; /* this must be conservative */
1056 h->cwraddr = conf.recovcw;
1058 h->roraddr = conf.recovro;
1063 p = getbuf(dev, baddr, Brd|Bmod);
1064 s = (Superb*)p->iobuf;
1066 memset(&s->fbuf, 0, sizeof(s->fbuf));
1067 s->fbuf.free[0] = 0;
1071 s->cwraddr = conf.recovcw;
1073 s->roraddr = conf.recovro;
1080 * calculate new buckets
1081 * initialize superblock.
1093 print("cwream %Z\n", dev);
1098 baddr = FIRST; /* baddr = super addr
1101 baddr+3 = reserved next superblock */
1103 cb = cacheinit(dev);
1104 h = (Cache*)cb->iobuf;
1107 h->cwraddr = baddr+1;
1108 h->roraddr = baddr+2;
1109 h->fsize = 0; /* prevents superream from freeing */
1114 cwio(dev, baddr+m, 0, Ogrow);
1115 superream(dev, baddr);
1116 rootream(dev, baddr+1); /* cw root */
1117 rootream(dev, baddr+2); /* ro root */
1119 cb = getbuf(cdev, CACHE_ADDR, Brd|Bmod|Bres);
1120 h = (Cache*)cb->iobuf;
1124 p = getbuf(dev, baddr, Brd|Bmod|Bimm);
1125 s = (Superb*)p->iobuf;
1127 s->cwraddr = baddr+1;
1128 s->roraddr = baddr+2;
1134 cwio(dev, baddr+m, 0, Odump);
1136 /* write superblock to worm */
1137 while(dumpblock(dev))
1142 rewalk1(Cw *cw, Off addr, int slot, Wpath *up)
1148 return cwraddr(cw->dev);
1149 up->addr = rewalk1(cw, up->addr, up->slot, up->up);
1150 p = getbuf(cw->dev, up->addr, Brd|Bmod);
1151 d = getdir(p, up->slot);
1152 if(!d || !(d->mode & DALLOC)) {
1153 fprint(2, "rewalk1 1\n");
1158 p1 = dnodebuf(p, d, slot/DIRPERBUF, 0, 0);
1160 fprint(2, "rewalk1 2\n");
1166 print("rewalk1 %lld to %lld \"%s\"\n",
1167 (Wideoff)addr, (Wideoff)p1->addr, d->name);
1176 rewalk2(Cw *cw, Off addr, int slot, Wpath *up)
1182 return cwraddr(cw->rodev);
1183 up->addr = rewalk2(cw, up->addr, up->slot, up->up);
1184 p = getbuf(cw->rodev, up->addr, Brd);
1185 d = getdir(p, up->slot);
1186 if(!d || !(d->mode & DALLOC)) {
1187 fprint(2, "rewalk2 1\n");
1192 p1 = dnodebuf(p, d, slot/DIRPERBUF, 0, 0);
1194 fprint(2, "rewalk2 2\n");
1200 print("rewalk2 %lld to %lld \"%s\"\n",
1201 (Wideoff)addr, (Wideoff)p1->addr, d->name);
1214 for(h=0; h<nelem(flist); h++)
1215 for(f=flist[h]; f; f=f->next) {
1218 if(cw->dev == f->fs->dev)
1219 f->addr = rewalk1(cw, f->addr, f->slot, f->wpath);
1221 if(cw->rodev == f->fs->dev)
1222 f->addr = rewalk2(cw, f->addr, f->slot, f->wpath);
1227 split(Cw *cw, Iobuf *p, Off addr)
1233 if(p && (p->flags & Bmod)) {
1239 state = cwio(cw->dev, addr, 0, Onone); /* read the state (twice?) */
1242 panic("split: unknown state %s", cwnames[state]);
1253 * botch.. could be done by relabeling
1256 p = getbuf(cw->dev, addr, Brd);
1258 fprint(2, "split: null getbuf\n");
1265 cwio(cw->dev, na, 0, Ogrow);
1266 cwio(cw->dev, na, p->iobuf, Owrite);
1267 cwio(cw->dev, na, 0, Odump);
1268 cwio(cw->dev, addr, 0, Orele);
1272 cwio(cw->dev, addr, 0, Odump);
1281 isdirty(Cw *cw, Iobuf *p, Off addr, int tag)
1285 if(p && (p->flags & Bmod))
1287 s = cwio(cw->dev, addr, 0, Onone);
1288 if(s == Cdirty || s == Cwrite)
1290 if(tag >= Tind1 && tag <= Tmaxind)
1291 /* botch, get these modified */
1298 cwrecur(Cw *cw, Off addr, int tag, int tag1, long qp)
1303 int i, j, shouldstop;
1308 p = getbuf(cw->dev, addr, Bprobe);
1309 if(!isdirty(cw, p, addr, tag)) {
1312 print("cwrecur: %lld t=%s not dirty %s\n",
1313 (Wideoff)addr, tagnames[tag], cw->name);
1321 print("cwrecur: %lld t=%s %s\n",
1322 (Wideoff)addr, tagnames[tag], cw->name);
1323 if(cw->depth >= 100) {
1324 fprint(2, "dump depth too great %s\n", cw->name);
1334 fprint(2, "cwrecur: unknown tag %d %s\n", tag, cw->name);
1342 p = getbuf(cw->dev, addr, Brd);
1343 if(!p || checktag(p, tag, qp)) {
1344 fprint(2, "cwrecur: Tdir p null %s\n", cw->name);
1353 cw->namepad[0] = 0; /* force room */
1354 np = strchr(cw->name, 0);
1361 for(i=0; i<DIRPERBUF; i++) {
1363 if(!(d->mode & DALLOC))
1367 qp1 = d->qid.path & ~QPDIR;
1369 strncpy(np, d->name, NAMELEN);
1371 fprint(2, "cwrecur: root with >1 directory\n");
1375 for(j=0; j<NDBLOCK; j++) {
1378 na = cwrecur(cw, na, tag1, 0, qp1);
1385 for (j = 0; j < NIBLOCK; j++) {
1388 na = cwrecur(cw, na, Tind1+j, tag1, qp1);
1397 for(i=0; i<DIRPERBUF; i++){
1399 if(!(d->mode & DALLOC))
1403 b = getbuf(devnone, Cwtmp, 0);
1404 memmove(b->iobuf, p->iobuf, RBUFSIZE);
1406 memset(d, 0, sizeof(Dentry));
1421 /* add more Tind tags here ... */
1426 p = getbuf(cw->dev, addr, Brd);
1427 if(!p || checktag(p, tag, qp)) {
1428 fprint(2, "cwrecur: Tind p null %s\n", cw->name);
1436 for(i=0; i<INDPERBUF; i++) {
1437 na = ((Off *)p->iobuf)[i];
1439 na = cwrecur(cw, na, j, tag1, qp);
1441 ((Off *)p->iobuf)[i] = na;
1449 na = split(cw, p, addr);
1454 p = getbuf(cw->dev, na ? na : addr, Brd);
1455 if(!p || checktag(p, tag, qp)){
1456 fprint(2, "cwrecur: b/p null\n");
1459 memmove(p->iobuf, b->iobuf, RBUFSIZE);
1460 p->flags |= Bmod|Bimm;
1469 if(cw->falsehits < 10)
1470 fprint(2, "shouldstop %lld %lld t=%s %s\n",
1471 (Wideoff)addr, (Wideoff)na,
1472 tagnames[tag], cw->name);
1480 Timet nextdump(Timet t);
1486 Off orba, rba, oroa, roa, sba, a;
1490 Dentry *dr, *d1, *d;
1495 if(fs->dev->type != Devcw) {
1496 fprint(2, "cant dump; not cw device: %Z\n", fs->dev);
1499 cw = fs->dev->private;
1501 fprint(2, "cant dump: has not been inited: %Z\n", fs->dev);
1506 wlock(&mainlock); /* dump */
1509 * set up static structure
1510 * with frequent variables
1519 sync("before dump");
1520 cw->fsize = cwsize(cw->dev);
1521 orba = cwraddr(cw->dev);
1523 print("cwroot %lld", (Wideoff)orba);
1525 cw->all = cw->allflag;
1526 rba = cwrecur(cw, orba, Tsuper, 0, QPROOT);
1530 print("->%lld\n", (Wideoff)rba);
1534 * partial super block
1536 p = getbuf(cw->dev, cwsaddr(cw->dev), Brd|Bmod|Bimm);
1537 s = (Superb*)p->iobuf;
1538 s->fsize = cw->fsize;
1543 * partial cache block
1545 p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bimm|Bres);
1546 h = (Cache*)p->iobuf;
1547 h->fsize = cw->fsize;
1554 oroa = cwraddr(cw->rodev);
1555 pr = getbuf(cw->dev, oroa, Brd|Bmod);
1558 datestr(tstr, time(nil)); /* tstr = "yyyymmdd" */
1561 p1 = dnodebuf(pr, dr, a, Tdir, 0);
1565 for(i=0; i<DIRPERBUF; i++) {
1569 if(!(d1->mode & DALLOC))
1571 if(!memcmp(d1->name, tstr, 4))
1572 goto found2; /* found entry */
1578 * no year directory, create one
1581 p = getbuf(cw->dev, rba, Brd);
1584 d1->qid.version += n;
1585 memmove(d1->name, tstr, 4);
1590 accessdir(p1, d1, FWRITE, 0);
1593 * put mmdd[count] in year directory
1596 accessdir(p1, d1, FREAD, 0);
1604 p1 = dnodebuf(pr, dr, a, Tdir, 0);
1608 for(i=0; i<DIRPERBUF; i++) {
1612 if(!(d1->mode & DALLOC))
1614 if(!memcmp(d1->name, tstr+4, 4))
1621 * empty slot put in root
1624 if(m) /* how many dumps this date */
1625 sprint(tstr+8, "%ld", m);
1627 p = getbuf(cw->dev, rba, Brd);
1629 *d1 = *d; /* qid is QPROOT */
1631 strcpy(d1->name, tstr+4);
1632 d1->qid.version += n;
1633 accessdir(p1, d1, FWRITE, 0);
1637 cw->fsize = cwsize(cw->dev);
1638 oroa = cwraddr(cw->rodev); /* probably redundant */
1640 print("roroot %lld", (Wideoff)oroa);
1644 roa = cwrecur(cw, oroa, Tsuper, 0, QPROOT);
1648 print("->%lld /%.4s/%s\n", (Wideoff)roa, tstr, tstr+4);
1654 a = cwsaddr(cw->dev);
1656 print("sblock %lld", (Wideoff)a);
1657 p = getbuf(cw->dev, a, Brd|Bmod|Bimm);
1658 s = (Superb*)p->iobuf;
1661 s->next = cw->fsize;
1663 s->fsize = cw->fsize;
1666 cwio(cw->dev, sba, 0, Ogrow);
1667 cwio(cw->dev, sba, p->iobuf, Owrite);
1668 cwio(cw->dev, sba, 0, Odump);
1670 print("->%lld (->%lld)\n", (Wideoff)sba, (Wideoff)s->next);
1677 p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bimm|Bres);
1678 h = (Cache*)p->iobuf;
1679 h->fsize = cw->fsize;
1688 print("%lld blocks queued for worm\n", (Wideoff)cw->ndump);
1689 print("%lld falsehits\n", (Wideoff)cw->falsehits);
1694 * extend all of the locks
1696 tim = toytime() - tim;
1697 for(i=0; i<NTLOCK; i++)
1698 if(tlocks[i].time > 0)
1699 tlocks[i].time += tim;
1702 nextdump(time(nil));
1710 mvstates(Device *dev, int s1, int s2, int side)
1716 Off m, lo, hi, msize, maddr;
1721 hi = lo + devsize(dev->cw.w); /* size of all sides totalled */
1723 /* operate on only a single disc side */
1726 wormsidestarts(dev, side, &ss);
1730 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
1731 if(!cb || checktag(cb, Tcache, QPSUPER))
1732 panic("cwstats: checktag c bucket");
1733 h = (Cache*)cb->iobuf;
1738 for(m=0; m<msize; m++) {
1739 p = getbuf(cw->cdev, maddr + m/BKPERBLK, Brd|Bmod);
1740 if(!p || checktag(p, Tbuck, maddr + m/BKPERBLK))
1741 panic("cwtest: checktag c bucket");
1742 b = (Bucket*)p->iobuf + m%BKPERBLK;
1743 ce = b->entry + CEPERBK;
1744 for(c=b->entry; c<ce; c++)
1745 if(c->state == s1 && c->waddr >= lo && c->waddr < hi)
1752 prchain(Device *dev, Off m, int flg)
1761 m = getstartsb(dev);
1763 p = getbuf(devnone, Cwxx2, 0);
1764 s = (Superb*)p->iobuf;
1766 memset(p->iobuf, 0, RBUFSIZE);
1767 if(devread(WDEV(dev), m, p->iobuf) ||
1768 checktag(p, Tsuper, QPSUPER))
1771 print("dump %lld is good; %lld prev\n", (Wideoff)m,
1773 print("\t%lld cwroot; %lld roroot\n",
1774 (Wideoff)s->cwraddr, (Wideoff)s->roraddr);
1779 print("dump %lld is good; %lld next\n", (Wideoff)m,
1781 print("\t%lld cwroot; %lld roroot\n",
1782 (Wideoff)s->cwraddr, (Wideoff)s->roraddr);
1792 touchsb(Device *dev)
1798 p = getbuf(devnone, Cwxx2, 0);
1800 memset(p->iobuf, 0, RBUFSIZE);
1801 if(devread(WDEV(dev), m, p->iobuf) ||
1802 checktag(p, Tsuper, QPSUPER))
1803 fprint(2, "%Z block %lld WORM SUPER BLOCK READ FAILED\n",
1804 WDEV(dev), (Wideoff)m);
1806 print("%Z touch superblock %lld\n", WDEV(dev), (Wideoff)m);
1811 storesb(Device *dev, Off last, int doit)
1818 sbaddr = cwsaddr(dev);
1820 ps = getbuf(devnone, Cwxx2, 0);
1822 fprint(2, "sbstore: getbuf\n");
1827 * try to read last sb
1829 memset(ps->iobuf, 0, RBUFSIZE);
1830 if(devread(WDEV(dev), last, ps->iobuf) ||
1831 checktag(ps, Tsuper, QPSUPER))
1832 print("read last failed\n");
1834 print("read last succeeded\n");
1836 s = (Superb*)ps->iobuf;
1841 if(s->next != sbaddr)
1842 print("next(last) is not sbaddr %lld %lld\n",
1843 (Wideoff)s->next, (Wideoff)sbaddr);
1845 print("next(last) is sbaddr\n");
1848 * read cached superblock
1850 ph = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
1851 if(!ph || checktag(ph, Tcache, QPSUPER)) {
1852 print("cwstats: checktag c bucket\n");
1858 print("read cached sb succeeded\n");
1860 h = (Cache*)ph->iobuf;
1862 memset(ps->iobuf, 0, RBUFSIZE);
1863 settag(ps, Tsuper, QPSUPER);
1865 s = (Superb*)ps->iobuf;
1867 s->cwraddr = h->cwraddr;
1868 s->roraddr = h->roraddr;
1869 s->fsize = h->fsize;
1872 s->next = h->roraddr+1;
1877 if(s->fsize-1 != s->next ||
1878 s->fsize-2 != s->roraddr ||
1879 s->fsize-5 != s->cwraddr) {
1880 print("addrs not in relationship %lld %lld %lld %lld\n",
1881 (Wideoff)s->cwraddr, (Wideoff)s->roraddr,
1882 (Wideoff)s->next, (Wideoff)s->fsize);
1886 print("addresses in relation\n");
1889 if(devwrite(WDEV(dev), sbaddr, ps->iobuf))
1890 print("%Z block %lld WORM SUPER BLOCK WRITE FAILED\n",
1891 WDEV(dev), (Wideoff)sbaddr);
1897 savecache(Device *dev)
1904 Off m, maddr, msize, *longp, nbyte;
1907 if(walkto("/adm/cache") || con_open(FID2, OWRITE|OTRUNC)) {
1908 fprint(2, "cant open /adm/cache\n");
1912 cb = getbuf(cdev, CACHE_ADDR, Brd|Bres);
1913 if(!cb || checktag(cb, Tcache, QPSUPER))
1914 panic("savecache: checktag c bucket");
1915 h = (Cache*)cb->iobuf;
1920 n = BUFSIZE; /* calculate write size */
1924 cb = getbuf(devnone, Cwxx4, 0);
1925 longp = (Off *)cb->iobuf;
1926 left = n/sizeof(Off);
1929 for(m=0; m<msize; m++) {
1930 if(left < BKPERBLK) {
1931 nbyte = (n/sizeof(Off) - left) * sizeof(Off);
1932 con_write(FID2, cb->iobuf, cons.offset, nbyte);
1933 cons.offset += nbyte;
1934 longp = (Off *)cb->iobuf;
1935 left = n/sizeof(Off);
1937 p = getbuf(cdev, maddr + m/BKPERBLK, Brd);
1938 if(!p || checktag(p, Tbuck, maddr + m/BKPERBLK))
1939 panic("cwtest: checktag c bucket");
1940 b = (Bucket*)p->iobuf + m%BKPERBLK;
1941 ce = b->entry + CEPERBK;
1942 for(c = b->entry; c < ce; c++)
1943 if(c->state == Cread) {
1944 *longp++ = c->waddr;
1949 nbyte = (n/sizeof(Off) - left) * sizeof(Off);
1950 con_write(FID2, cb->iobuf, cons.offset, nbyte);
1955 loadcache(Device *dev, int dskno)
1958 Off m, nbyte, *longp, count;
1961 if(walkto("/adm/cache") || con_open(FID2, OREAD)) {
1962 fprint(2, "cant open /adm/cache\n");
1966 cb = getbuf(devnone, Cwxx4, 0);
1971 wormsidestarts(dev, dskno, &ss);
1973 memset(cb->iobuf, 0, BUFSIZE);
1974 nbyte = con_read(FID2, cb->iobuf, cons.offset, 100) / sizeof(Off);
1977 cons.offset += nbyte * sizeof(Off);
1978 longp = (Off *)cb->iobuf;
1984 /* if given a diskno, restrict to just that disc side */
1985 if(dskno < 0 || m >= ss.sstart && m < ss.s1start) {
1986 p = getbuf(dev, m, Brd);
1994 print("%lld blocks loaded from worm %d\n", (Wideoff)count, dskno);
1998 morecache(Device *dev, int dskno, Off size)
2001 Off m, ml, mh, mm, count;
2005 p = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
2006 if(!p || checktag(p, Tcache, QPSUPER))
2007 panic("savecache: checktag c bucket");
2008 h = (Cache*)p->iobuf;
2012 wormsidestarts(dev, dskno, &ss);
2013 ml = ss.sstart; /* start at beginning of disc side #dskno */
2017 print("limited to %lld\n", (Wideoff)mh-ml);
2021 for(m=ml; m < mh; m++) {
2022 p = getbuf(dev, m, Brd);
2027 print("%lld blocks loaded from worm %d\n", (Wideoff)count, dskno);
2031 blockcmp(Device *dev, Off wa, Off ca)
2036 p1 = getbuf(WDEV(dev), wa, Brd);
2038 fprint(2, "blockcmp: wdev error\n");
2042 p2 = getbuf(CDEV(dev), ca, Brd);
2044 fprint(2, "blockcmp: cdev error\n");
2050 for(i=0; i<RBUFSIZE; i++)
2051 if(p1->iobuf[i] != p2->iobuf[i]) {
2052 print("%4d: %.2x %.2x\n",
2066 wblock(Device *dev, Off addr)
2071 p1 = getbuf(dev, addr, Brd);
2073 i = devwrite(WDEV(dev), addr, p1->iobuf);
2074 print("i = %d\n", i);
2085 /* garbage to change sb size
2086 * probably will need it someday
2088 fsz = number(0, 0, 10);
2090 if(fsz == number(0, -1, 10))
2091 count = -1; /* really do it */
2092 print("fsize = %ld\n", fsz);
2094 cb = getbuf(cdev, CACHE_ADDR, Brd|Bres);
2095 if(!cb || checktag(cb, Tcache, QPSUPER))
2096 panic("cwstats: checktag c bucket");
2097 h = (Cache*)cb->iobuf;
2098 for(m=0; m<h->msize; m++) {
2099 p = getbuf(cdev, h->maddr + m/BKPERBLK, Brd|Bmod);
2100 if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK))
2101 panic("cwtest: checktag c bucket");
2102 b = (Bucket*)p->iobuf + m%BKPERBLK;
2103 ce = b->entry + CEPERBK;
2104 for(c=b->entry; c<ce; c++) {
2111 if(c->state != Cdirty)
2117 print("old cache hsize = %ld\n", h->fsize);
2120 p = getbuf(dev, h->sbaddr, Brd|Bmod);
2121 s = (Superb*)p->iobuf;
2122 print("old super hsize = %ld\n", s->fsize);
2127 print("count = %lld\n", (Wideoff)count);
2131 convstate(char *name)
2135 for(i=0; i<nelem(cwnames); i++)
2137 if(strcmp(cwnames[i], name) == 0)
2143 searchtag(Device *d, Off a, int tag, int n)
2151 p = getbuf(devnone, Cwxx2, 0);
2152 t = (Tag*)(p->iobuf+BUFSIZE);
2153 for(i=0; i<n; i++) {
2154 memset(p->iobuf, 0, RBUFSIZE);
2155 if(devread(WDEV(d), a+i, p->iobuf)) {
2161 print("tag %d found at %Z %lld\n", tag, d, (Wideoff)a+i);
2169 cmd_cwcmd(int argc, char *argv[])
2174 Off s1, s2, a, b, n;
2178 print("\tcwcmd mvstate state1 state2 [platter]\n");
2179 print("\tcwcmd prchain [start] [bakflg]\n");
2180 print("\tcwcmd searchtag [start] [tag] [blocks]\n");
2181 print("\tcwcmd touchsb\n");
2182 print("\tcwcmd savecache\n");
2183 print("\tcwcmd loadcache [dskno]\n");
2184 print("\tcwcmd morecache dskno [count]\n");
2185 print("\tcwcmd blockcmp wbno cbno\n");
2186 print("\tcwcmd startdump [01]\n");
2187 print("\tcwcmd acct\n");
2188 print("\tcwcmd clearacct\n");
2194 * items not depend on a cw filesystem
2196 if(strcmp(arg, "acct") == 0) {
2197 for(a=0; a<nelem(growacct); a++) {
2200 uidtostr(str, a, 1);
2201 print("%10lld %s\n",
2202 ((Wideoff)b*ADDFREE*RBUFSIZE+500000)/1000000,
2208 if(strcmp(arg, "clearacct") == 0) {
2209 memset(growacct, 0, sizeof(growacct));
2214 * items depend on cw filesystem
2216 dev = cons.curfs->dev;
2217 if(dev == 0 || dev->type != Devcw || dev->private == 0) {
2218 print("cfs not a cw filesystem: %Z\n", dev);
2222 if(strcmp(arg, "searchtag") == 0) {
2225 a = number(argv[2], 0, 10);
2228 b = number(argv[3], 0, 10);
2231 n = number(argv[4], 0, 10);
2232 searchtag(dev, a, b, n);
2233 } else if(strcmp(arg, "mvstate") == 0) {
2236 s1 = convstate(argv[2]);
2237 s2 = convstate(argv[3]);
2238 if(s1 < 0 || s2 < 0)
2242 a = number(argv[4], 0, 10);
2243 mvstates(dev, s1, s2, a);
2246 print("cwcmd mvstate: bad args\n");
2247 } else if(strcmp(arg, "prchain") == 0) {
2250 a = number(argv[2], 0, 10);
2253 s1 = number(argv[3], 0, 10);
2254 prchain(dev, a, s1);
2255 } else if(strcmp(arg, "touchsb") == 0)
2257 else if(strcmp(arg, "savecache") == 0)
2259 else if(strcmp(arg, "loadcache") == 0) {
2262 s1 = number(argv[2], 0, 10);
2264 } else if(strcmp(arg, "morecache") == 0) {
2266 print("arg count\n");
2269 s1 = number(argv[2], 0, 10);
2271 s2 = number(argv[3], 0, 10);
2273 s2 = wormsizeside(dev, s1); /* default to 1 disc side */
2274 morecache(dev, s1, s2);
2275 } else if(strcmp(arg, "blockcmp") == 0) {
2277 print("cannot arg count\n");
2280 s1 = number(argv[2], 0, 10);
2281 s2 = number(argv[3], 0, 10);
2282 blockcmp(dev, s1, s2);
2283 } else if(strcmp(arg, "startdump") == 0) {
2285 cw->nodump = number(argv[2], 0, 10);
2286 cw->nodump = !cw->nodump;
2288 print("dump stopped\n");
2290 print("dump allowed\n");
2291 } else if(strcmp(arg, "allflag") == 0) {
2293 cw->allflag = number(argv[2], 0, 10);
2295 cw->allflag = !cw->allflag;
2296 print("allflag = %d; falsehits = %lld\n",
2297 cw->allflag, (Wideoff)cw->falsehits);
2298 } else if(strcmp(arg, "storesb") == 0) {
2302 a = number(argv[2], 4168344, 10);
2304 b = number(argv[3], 0, 10);
2306 } else if(strcmp(arg, "test") == 0)
2309 print("unknown cwcmd %s\n", arg);