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
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 */
66 char namepad[NAMELEN+10];
70 static char* cwnames[] =
88 Centry* getcentry(Bucket*, Off);
89 int cwio(Device*, Off, void*, int);
90 void cmd_cwcmd(int, char*[]);
97 cmd_dump(int argc, char *argv[])
105 print("%s: unknown file system\n", argv[1]);
116 cmd_statw(int, char*[])
124 Off m, nw, bw, state[Onone];
125 Off sbfsize, sbcwraddr, sbroraddr, sblast, sbnext;
126 Off hmsize, hmaddr, dsize, dsizepct;
133 if(dev->type != Devcw) {
134 print("curfs not type cw\n");
140 print("curfs not inited\n");
144 print("cwstats %s\n", fs->name);
152 print("\tfilesys %s\n", fs->name);
153 // print("\tnio =%7W%7W%7W\n", cw->ncwio+0, cw->ncwio+1, cw->ncwio+2);
154 p = getbuf(dev, cwsaddr(dev), Brd);
155 if(!p || checktag(p, Tsuper, QPSUPER)) {
156 print("cwstats: checktag super\n");
163 sb = (Superb*)p->iobuf;
165 sbcwraddr = sb->cwraddr;
166 sbroraddr = sb->roraddr;
172 p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
173 if(!p || checktag(p, Tcache, QPSUPER)) {
174 print("cwstats: checktag super\n");
179 h = (Cache*)p->iobuf;
183 print("\t\tmaddr = %8lld\n", (Wideoff)hmaddr);
184 print("\t\tmsize = %8lld\n", (Wideoff)hmsize);
185 print("\t\tcaddr = %8lld\n", (Wideoff)h->caddr);
186 print("\t\tcsize = %8lld\n", (Wideoff)h->csize);
187 print("\t\tsbaddr = %8lld\n", (Wideoff)h->sbaddr);
188 print("\t\tcraddr = %8lld %8lld\n",
189 (Wideoff)h->cwraddr, (Wideoff)sbcwraddr);
190 print("\t\troaddr = %8lld %8lld\n",
191 (Wideoff)h->roraddr, (Wideoff)sbroraddr);
192 /* print stats in terms of (first-)disc sides */
193 dsize = wormsizeside(dev, 0);
195 dsize = h->wsize; /* it's probably a fake worm */
197 dsize = 1000; /* don't divide by zero */
199 dsizepct = dsize/100;
200 print("\t\tfsize = %8lld %8lld %2lld+%2lld%%\n", (Wideoff)h->fsize,
201 (Wideoff)sbfsize, (Wideoff)h->fsize/dsize,
202 (Wideoff)(h->fsize%dsize)/dsizepct);
203 print("\t\tslast = %8lld\n", (Wideoff)sblast);
204 print("\t\tsnext = %8lld\n", (Wideoff)sbnext);
205 print("\t\twmax = %8lld %2lld+%2lld%%\n",
206 (Wideoff)h->wmax, (Wideoff)h->wmax/dsize,
207 (Wideoff)(h->wmax%dsize)/dsizepct);
208 print("\t\twsize = %8lld %2lld+%2lld%%\n",
209 (Wideoff)h->wsize, (Wideoff)h->wsize/dsize,
210 (Wideoff)(h->wsize%dsize)/dsizepct);
213 bw = 0; /* max filled bucket */
214 memset(state, 0, sizeof(state));
215 for(m = 0; m < hmsize; m++) {
216 p = getbuf(cw->cdev, hmaddr + m/BKPERBLK, Brd);
217 if(!p || checktag(p, Tbuck, hmaddr + m/BKPERBLK)) {
218 print("cwstats: checktag c bucket\n");
223 b = (Bucket*)p->iobuf + m%BKPERBLK;
224 ce = b->entry + CEPERBK;
226 for(c = b->entry; c < ce; c++) {
229 if(s != Cnone && s != Cread)
236 for(s = Cnone; s < Cerror; s++)
237 print("\t\t%6lld %s\n", (Wideoff)state[s], cwnames[s]);
238 print("\t\tcache %2lld%% full\n", ((Wideoff)bw*100)/CEPERBK);
242 dumpblock(Device *dev)
244 Iobuf *p, *cb, *p1, *p2;
248 Off m, a, bn, msize, maddr, wmax, caddr;
253 if(cw == 0 || cw->nodump)
256 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
257 h = (Cache*)cb->iobuf;
264 for(m=msize; m>=0; m--) {
265 bn = cw->dbucket + 1;
266 if(bn < 0 || bn >= msize)
269 a = maddr + bn/BKPERBLK;
270 p = getbuf(cw->cdev, a, Brd);
271 if(!p || checktag(p, Tbuck, a)) {
272 fprint(2, "dump: checktag c bucket\n");
277 b = (Bucket*)p->iobuf + bn%BKPERBLK;
278 ce = b->entry + CEPERBK;
280 for(c = b->entry; c < ce; c++)
281 if(c->state == Cdump) {
286 if(c->waddr < cw->daddr) {
287 if(bc->waddr < cw->daddr &&
288 bc->waddr > c->waddr)
292 if(bc->waddr < cw->daddr ||
293 bc->waddr > c->waddr)
304 fprint(2, "%lld blocks copied to worm\n", (Wideoff)cw->ncopy);
312 a = bn + (c - b->entry)*msize + caddr;
314 a = bn*CEPERBK + (c - b->entry) + caddr;
315 p1 = getbuf(devnone, Cwdump1, 0);
320 if(count > 10 || devread(cw->cdev, a, p1->iobuf)) {
327 s1 = devwrite(cw->wdev, m, p1->iobuf);
329 p2 = getbuf(devnone, Cwdump2, 0);
330 s2 = devread(cw->wdev, m, p2->iobuf);
332 if(s1 == 0x61 && s2 == 0x60) {
338 if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE))
345 if(conf.dumpreread) {
346 p2 = getbuf(devnone, Cwdump2, 0);
347 s1 = devread(cw->wdev, m, p2->iobuf);
350 if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) {
351 fprint(2, "reread C%lld W%lld didnt compare\n",
352 (Wideoff)a, (Wideoff)m);
364 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres);
365 h = (Cache*)cb->iobuf;
382 fprint(2, "stopping dump!!\n");
398 cmd_install("dump", "-- make dump backup to worm", cmd_dump);
399 cmd_install("statw", "-- cache/worm stats", cmd_statw);
400 cmd_install("cwcmd", "subcommand -- cache/worm errata", cmd_cwcmd);
401 roflag = flag_install("ro", "-- ro reads and writes");
404 cw = ialloc(sizeof(Cw), 0);
410 cw->cdev = CDEV(dev);
411 cw->wdev = WDEV(dev);
412 cw->rodev = RDEV(dev);
429 l = devsize(cw->wdev);
430 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres);
431 if(!cb || checktag(cb, Tcache, QPSUPER))
432 panic("cwinit: checktag super");
433 h = (Cache*)cb->iobuf;
434 h->toytime = toytime() + SECOND(30);
439 fprint(2, "wdev changed size %lld to %lld\n",
440 (Wideoff)m, (Wideoff)l);
446 for(m=0; m<h->msize; m++) {
447 p = getbuf(cw->cdev, h->maddr + m/BKPERBLK, Brd);
448 if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK))
449 panic("cwinit: checktag c bucket");
461 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
462 sa = ((Cache*)cb->iobuf)->sbaddr;
475 fprint(2, "unknown dev in cwraddr %Z\n", dev);
479 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
480 ra = ((Cache*)cb->iobuf)->cwraddr;
484 cb = getbuf(CDEV(dev->ro.parent), CACHE_ADDR, Brd|Bres);
485 ra = ((Cache*)cb->iobuf)->roraddr;
498 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
499 fs = ((Cache*)cb->iobuf)->fsize;
505 cwread(Device *dev, Off b, void *c)
507 return cwio(dev, b, c, Oread) == Cerror;
511 cwwrite(Device *dev, Off b, void *c)
513 return cwio(dev, b, c, Owrite) == Cerror;
517 roread(Device *dev, Off b, void *c)
523 * maybe better is to try buffer pool first
526 if(d == 0 || d->type != Devcw ||
527 d->private == 0 || RDEV(d) != dev) {
528 fprint(2, "bad rodev %Z\n", dev);
531 s = cwio(d, b, 0, Onone);
532 if(s == Cdump || s == Cdump1 || s == Cread) {
533 s = cwio(d, b, c, Oread);
534 if(s == Cdump || s == Cdump1 || s == Cread) {
535 if(cons.flags & roflag)
536 fprint(2, "roread: %Z %lld -> %Z(hit)\n",
541 if(cons.flags & roflag)
542 fprint(2, "roread: %Z %lld -> %Z(miss)\n",
543 dev, (Wideoff)b, WDEV(d));
544 return devread(WDEV(d), b, c);
548 cwio(Device *dev, Off addr, void *buf, int opcode)
550 Iobuf *p, *p1, *p2, *cb;
554 Off bn, a1, a2, max, newmax;
560 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
561 h = (Cache*)cb->iobuf;
562 if(toytime() >= h->toytime) {
564 h->toytime = toytime() + SECOND(30);
573 bn = addr % h->msize;
574 a1 = h->maddr + bn/BKPERBLK;
578 a2 = bn*CEPERBK + h->caddr;
584 p = getbuf(cw->cdev, a1, Brd|Bmod);
585 if(!p || checktag(p, Tbuck, a1))
586 panic("cwio: checktag c bucket");
587 b = (Bucket*)p->iobuf + bn%BKPERBLK;
589 c = getcentry(b, addr);
592 fprint(2, "%Z disk cache bucket %lld is full\n",
593 cw->cdev, (Wideoff)a1);
597 a2 += (c - b->entry) * h->msize;
615 if(!devread(cw->cdev, a2, buf))
620 if(devread(cw->wdev, addr, buf)) {
626 if(!devwrite(cw->cdev, a2, buf))
634 if(devread(cw->cdev, a2, buf))
648 * this is hard part -- a dump block must be
649 * sent to the worm if it is rewritten.
650 * if this causes an error, there is no
651 * place to save the dump1 data. the block
652 * is just reclassified as 'dump1' (botch)
654 p1 = getbuf(devnone, Cwio1, 0);
655 if(devread(cw->cdev, a2, p1->iobuf)) {
657 fprint(2, "cwio: write induced dump error - r cache\n");
660 if(devwrite(cw->cdev, a2, buf)) {
667 if(devwrite(cw->wdev, addr, p1->iobuf)) {
668 p2 = getbuf(devnone, Cwio2, 0);
669 if(devread(cw->wdev, addr, p2->iobuf)) {
672 fprint(2, "cwio: write induced dump error - r+w worm\n");
675 if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) {
678 fprint(2, "cwio: write induced dump error - w worm\n");
691 if(devwrite(cw->cdev, a2, buf)) {
700 if(devwrite(cw->cdev, a2, buf))
708 fprint(2, "%Z for block %lld cwgrow with state = %s\n",
709 cw->cdev, (Wideoff)addr, cwnames[state]);
716 if(state != Cdirty) { /* BOTCH */
717 fprint(2, "%Z for block %lld cwdump with state = %s\n",
718 cw->cdev, (Wideoff)addr, cwnames[state]);
722 cw->ndump++; /* only called from dump command */
726 if(state != Cwrite) {
728 fprint(2, "%Z for block %lld cwrele with state = %s\n",
729 cw->cdev, (Wideoff)addr, cwnames[state]);
736 if(state == Cwrite || state == Cread)
741 fprint(2, "cwio: %Z %lld s=%s o=%s ns=%s\n",
742 dev, (Wideoff)addr, cwnames[state],
747 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres);
748 h = (Cache*)cb->iobuf;
756 fprint(2, "%Z block %lld cw state = %s; cw opcode = %s",
757 dev, (Wideoff)addr, cwnames[state], cwnames[opcode]);
763 cwgrow(Device *dev, Superb *sb, int)
769 cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bmod|Bres);
770 h = (Cache*)cb->iobuf;
784 for(nfs--; nfs>=fs; nfs--)
785 switch(cwio(dev, nfs, 0, Ogrow)) {
789 addfree(dev, nfs, sb);
795 cwfree(Device *dev, Off addr)
799 if(dev->type == Devcw) {
800 state = cwio(dev, addr, 0, Ofree);
802 return 1; /* do not put in freelist */
804 return 0; /* put in freelist */
811 Centry *c, *c1, *c2, *ce;
815 if(b->agegen < CEPERBK || b->agegen > MAXAGE) {
816 print("agegen %ld\n", b->agegen);
820 ce = b->entry + CEPERBK;
821 c1 = 0; /* lowest age last pass */
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);
830 if(c1->waddr == c->waddr)
831 if(c1->state != Cnone)
832 if(c->state != Cnone) {
833 print("same waddr %lld\n",
838 if(c1 != 0 && c->age <= c1->age)
840 if(c2 == 0 || c->age < c2->age)
846 if(c1->age >= b->agegen) {
847 print("age >= generator %d %ld\n", c1->age, b->agegen);
856 resequence(Bucket *b)
861 ce = b->entry + CEPERBK;
862 for(c = b->entry; c < ce; c++) {
867 b->agegen += CEPERBK;
872 for(c = b->entry; c < ce; c++) {
875 if(cr == 0 || c->age < age) {
889 getcentry(Bucket *b, Off addr)
895 * search for cache hit
896 * find oldest block as byproduct
898 ce = b->entry + CEPERBK;
901 for(c = b->entry; c < ce; c++) {
911 if(cr == 0 || c->age < age) {
922 return 0; /* bucket is full */
929 * update the age to get filo cache.
930 * small number in age means old
932 if(!cons.noage || c->state == Cnone) {
937 if(age < 0 || age >= MAXAGE)
945 * calculate new buckets
948 cacheinit(Device *dev)
956 print("cache init %Z\n", dev);
960 cb = getbuf(cdev, CACHE_ADDR, Bmod|Bres);
961 memset(cb->iobuf, 0, RBUFSIZE);
962 settag(cb, Tcache, QPSUPER);
963 h = (Cache*)cb->iobuf;
966 * calculate csize such that
967 * tsize = msize/BKPERBLK + csize and
968 * msize = csize/CEPERBK
970 h->maddr = CACHE_ADDR + 1;
971 m = devsize(cdev) - h->maddr;
972 h->csize = ((Devsize)(m-1) * CEPERBK*BKPERBLK) / (CEPERBK*BKPERBLK+1);
973 h->msize = h->csize/CEPERBK - 5;
974 while(!prime(h->msize))
976 h->csize = h->msize*CEPERBK;
977 h->caddr = h->maddr + (h->msize+BKPERBLK-1)/BKPERBLK;
978 h->wsize = devsize(WDEV(dev));
981 panic("cache too small");
982 if(h->caddr + h->csize > m)
983 panic("cache size error");
988 for(m=h->maddr; m<h->caddr; m++) {
989 p = getbuf(cdev, m, Bmod);
990 memset(p->iobuf, 0, RBUFSIZE);
998 getstartsb(Device *dev)
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)
1008 fprint(2, "getstartsb: no special starting superblock for %Z %s\n",
1013 fprint(2, "getstartsb: no filsys for device %Z\n", dev);
1019 * calculate new buckets
1020 * get superblock from
1021 * last worm dump block.
1024 cwrecover(Device *dev)
1033 print("cwrecover %Z\n", dev);
1037 p = getbuf(devnone, Cwxx1, 0);
1038 s = (Superb*)p->iobuf;
1040 m = getstartsb(dev);
1045 memset(p->iobuf, 0, RBUFSIZE);
1046 if(devread(wdev, m, p->iobuf) ||
1047 checktag(p, Tsuper, QPSUPER))
1052 print("dump %lld is good; %lld next\n", (Wideoff)baddr, (Wideoff)m);
1053 if(baddr == conf.recovsb)
1058 panic("recover: no superblock");
1060 p = getbuf(wdev, baddr, Brd);
1061 s = (Superb*)p->iobuf;
1063 cb = cacheinit(dev);
1064 h = (Cache*)cb->iobuf;
1066 h->cwraddr = s->cwraddr;
1067 h->roraddr = s->roraddr;
1068 h->fsize = s->fsize + 100; /* this must be conservative */
1070 h->cwraddr = conf.recovcw;
1072 h->roraddr = conf.recovro;
1077 p = getbuf(dev, baddr, Brd|Bmod);
1078 s = (Superb*)p->iobuf;
1080 memset(&s->fbuf, 0, sizeof(s->fbuf));
1081 s->fbuf.free[0] = 0;
1085 s->cwraddr = conf.recovcw;
1087 s->roraddr = conf.recovro;
1094 * calculate new buckets
1095 * initialize superblock.
1107 print("cwream %Z\n", dev);
1112 baddr = FIRST; /* baddr = super addr
1115 baddr+3 = reserved next superblock */
1117 cb = cacheinit(dev);
1118 h = (Cache*)cb->iobuf;
1121 h->cwraddr = baddr+1;
1122 h->roraddr = baddr+2;
1123 h->fsize = 0; /* prevents superream from freeing */
1128 cwio(dev, baddr+m, 0, Ogrow);
1129 superream(dev, baddr);
1130 rootream(dev, baddr+1); /* cw root */
1131 rootream(dev, baddr+2); /* ro root */
1133 cb = getbuf(cdev, CACHE_ADDR, Brd|Bmod|Bres);
1134 h = (Cache*)cb->iobuf;
1138 p = getbuf(dev, baddr, Brd|Bmod|Bimm);
1139 s = (Superb*)p->iobuf;
1141 s->cwraddr = baddr+1;
1142 s->roraddr = baddr+2;
1148 cwio(dev, baddr+m, 0, Odump);
1150 /* write superblock to worm */
1151 while(dumpblock(dev))
1156 rewalk1(Cw *cw, Off addr, int slot, Wpath *up)
1162 return cwraddr(cw->dev);
1163 up->addr = rewalk1(cw, up->addr, up->slot, up->up);
1164 p = getbuf(cw->dev, up->addr, Brd|Bmod);
1165 d = getdir(p, up->slot);
1166 if(!d || !(d->mode & DALLOC)) {
1167 fprint(2, "rewalk1 1\n");
1172 p1 = dnodebuf(p, d, slot/DIRPERBUF, 0, 0);
1174 fprint(2, "rewalk1 2\n");
1180 fprint(2, "rewalk1 %lld to %lld \"%s\"\n",
1181 (Wideoff)addr, (Wideoff)p1->addr, d->name);
1190 rewalk2(Cw *cw, Off addr, int slot, Wpath *up)
1196 return cwraddr(cw->rodev);
1197 up->addr = rewalk2(cw, up->addr, up->slot, up->up);
1198 p = getbuf(cw->rodev, up->addr, Brd);
1199 d = getdir(p, up->slot);
1200 if(!d || !(d->mode & DALLOC)) {
1201 fprint(2, "rewalk2 1\n");
1206 p1 = dnodebuf(p, d, slot/DIRPERBUF, 0, 0);
1208 fprint(2, "rewalk2 2\n");
1214 fprint(2, "rewalk2 %lld to %lld \"%s\"\n",
1215 (Wideoff)addr, (Wideoff)p1->addr, d->name);
1228 for(h=0; h<nelem(flist); h++)
1229 for(f=flist[h]; f; f=f->next) {
1232 if(cw->dev == f->fs->dev)
1233 f->addr = rewalk1(cw, f->addr, f->slot, f->wpath);
1235 if(cw->rodev == f->fs->dev)
1236 f->addr = rewalk2(cw, f->addr, f->slot, f->wpath);
1241 split(Cw *cw, Iobuf *p, Off addr)
1247 if(p && (p->flags & Bmod)) {
1253 state = cwio(cw->dev, addr, 0, Onone); /* read the state (twice?) */
1256 panic("split: unknown state %s", cwnames[state]);
1267 if(cw->fsize >= cw->wsize)
1271 * botch.. could be done by relabeling
1274 p = getbuf(cw->dev, addr, Brd);
1276 fprint(2, "split: null getbuf\n");
1281 cwio(cw->dev, na, 0, Ogrow);
1282 cwio(cw->dev, na, p->iobuf, Owrite);
1283 cwio(cw->dev, na, 0, Odump);
1284 cwio(cw->dev, addr, 0, Orele);
1288 cwio(cw->dev, addr, 0, Odump);
1297 isdirty(Cw *cw, Iobuf *p, Off addr, int tag)
1301 if(p && (p->flags & Bmod))
1303 s = cwio(cw->dev, addr, 0, Onone);
1304 if(s == Cdirty || s == Cwrite)
1306 if(tag >= Tind1 && tag <= Tmaxind)
1307 /* botch, get these modified */
1314 cwrecur(Cw *cw, Off addr, int tag, int tag1, long qp)
1319 int i, j, shouldstop;
1324 p = getbuf(cw->dev, addr, Bprobe);
1325 if(!isdirty(cw, p, addr, tag)) {
1328 fprint(2, "cwrecur: %lld t=%s not dirty %s\n",
1329 (Wideoff)addr, tagnames[tag], cw->name);
1337 fprint(2, "cwrecur: %lld t=%s %s\n",
1338 (Wideoff)addr, tagnames[tag], cw->name);
1339 if(cw->depth >= 100) {
1340 fprint(2, "dump depth too great %s\n", cw->name);
1349 fprint(2, "cwrecur: unknown tag %d %s\n", tag, cw->name);
1353 if(p && checktag(p, tag, qp))
1354 fprint(2, "cwrecur: Tfile %s\n", cw->name);
1359 cw->namepad[0] = 0; /* force room */
1360 np = strchr(cw->name, 0);
1367 p = getbuf(cw->dev, addr, Brd);
1368 if(!p || checktag(p, tag, qp)) {
1369 fprint(2, "cwrecur: Tdir %s\n", cw->name);
1372 for(i=0; i<DIRPERBUF; i++) {
1374 if((d->mode & (DALLOC|DTMP)) != DALLOC)
1376 qp1 = d->qid.path & ~QPDIR;
1378 strncpy(np, d->name, NAMELEN);
1380 fprint(2, "cwrecur: root with >1 directory\n");
1384 for(j=0; j<NDBLOCK; j++) {
1387 na = cwrecur(cw, na, tag1, 0, qp1);
1394 for (j = 0; j < NIBLOCK; j++) {
1397 na = cwrecur(cw, na, Tind1+j, tag1, qp1);
1416 /* add more Tind tags here ... */
1421 p = getbuf(cw->dev, addr, Brd);
1422 if(!p || checktag(p, tag, qp)) {
1423 fprint(2, "cwrecur: Tind %s\n", cw->name);
1426 for(i=0; i<INDPERBUF; i++) {
1427 na = ((Off *)p->iobuf)[i];
1429 na = cwrecur(cw, na, j, tag1, qp);
1431 ((Off *)p->iobuf)[i] = na;
1439 na = split(cw, p, addr);
1445 if(cw->allflag && cw->falsehits < 10)
1446 fprint(2, "shouldstop %lld %lld t=%s %s\n",
1447 (Wideoff)addr, (Wideoff)na,
1448 tagnames[tag], cw->name);
1456 Timet nextdump(Timet t);
1462 Off orba, rba, oroa, roa, sba, a;
1466 Dentry *dr, *d1, *d;
1471 if(fs->dev->type != Devcw) {
1472 fprint(2, "cant dump; not cw device: %Z\n", fs->dev);
1475 cw = fs->dev->private;
1477 fprint(2, "cant dump: has not been inited: %Z\n", fs->dev);
1482 wlock(&mainlock); /* dump */
1485 * set up static structure
1486 * with frequent variables
1495 sync("before dump");
1496 cw->fsize = cwsize(cw->dev);
1497 orba = cwraddr(cw->dev);
1499 fprint(2, "cwroot %lld", (Wideoff)orba);
1501 cw->all = cw->allflag | noatime | noatimeset;
1503 rba = cwrecur(cw, orba, Tdir, 0, QPROOT);
1507 fprint(2, "->%lld\n", (Wideoff)rba);
1511 * partial super block
1513 p = getbuf(cw->dev, cwsaddr(cw->dev), Brd|Bmod|Bimm);
1514 if(!p || checktag(p, Tsuper, QPSUPER))
1516 s = (Superb*)p->iobuf;
1517 s->fsize = cw->fsize;
1522 * partial cache block
1524 p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bimm|Bres);
1525 if(!p || checktag(p, Tcache, QPSUPER))
1527 h = (Cache*)p->iobuf;
1528 h->fsize = cw->fsize;
1532 if(cw->fsize+50 > cw->wsize){
1533 fprint(2, "dump: worm full after dump\n");
1540 oroa = cwraddr(cw->rodev);
1541 pr = getbuf(cw->dev, oroa, Brd|Bmod);
1542 if(!pr || checktag(pr, Tdir, QPROOT))
1546 datestr(tstr, time(nil)); /* tstr = "yyyymmdd" */
1549 p1 = dnodebuf(pr, dr, a, Tdir, 0);
1550 if(!p1 || checktag(p1, Tdir, QPNONE))
1553 for(i=0; i<DIRPERBUF; i++) {
1557 if(!(d1->mode & DALLOC))
1559 if(!memcmp(d1->name, tstr, 4))
1560 goto found2; /* found entry */
1566 * no year directory, create one
1569 p = getbuf(cw->dev, rba, Brd);
1570 if(!p || checktag(p, Tdir, QPROOT))
1574 d1->qid.version += n;
1575 memmove(d1->name, tstr, 4);
1580 accessdir(pr, dr, FWRITE, 0);
1583 * put mmdd[count] in year directory
1586 accessdir(pr, dr, FREAD, 0);
1594 p1 = dnodebuf(pr, dr, a, Tdir, 0);
1595 if(!p1 || checktag(p1, Tdir, QPNONE))
1598 for(i=0; i<DIRPERBUF; i++) {
1602 if(!(d1->mode & DALLOC))
1604 if(!memcmp(d1->name, tstr+4, 4))
1611 * empty slot put in root
1614 if(m) /* how many dumps this date */
1615 sprint(tstr+8, "%ld", m);
1617 p = getbuf(cw->dev, rba, Brd);
1618 if(!p || checktag(p, Tdir, QPROOT))
1621 *d1 = *d; /* qid is QPROOT */
1623 strcpy(d1->name, tstr+4);
1624 d1->qid.version += n;
1625 accessdir(p1, d1, FWRITE, 0);
1627 accessdir(pr, dr, FWRITE, 0);
1630 cw->fsize = cwsize(cw->dev);
1631 oroa = cwraddr(cw->rodev); /* probably redundant */
1633 fprint(2, "roroot %lld", (Wideoff)oroa);
1637 roa = cwrecur(cw, oroa, Tdir, 0, QPROOT);
1641 fprint(2, "->%lld /%.4s/%s\n", (Wideoff)roa, tstr, tstr+4);
1647 a = cwsaddr(cw->dev);
1649 fprint(2, "sblock %lld", (Wideoff)a);
1650 p = getbuf(cw->dev, a, Brd|Bmod|Bimm);
1651 if(!p || checktag(p, Tsuper, QPSUPER))
1653 s = (Superb*)p->iobuf;
1656 s->next = cw->fsize++;
1657 s->fsize = cw->fsize;
1660 cwio(cw->dev, sba, 0, Ogrow);
1661 cwio(cw->dev, sba, p->iobuf, Owrite);
1662 cwio(cw->dev, sba, 0, Odump);
1664 fprint(2, "->%lld (->%lld)\n", (Wideoff)sba, (Wideoff)s->next);
1671 p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bimm|Bres);
1672 if(!p || checktag(p, Tcache, QPSUPER))
1674 h = (Cache*)p->iobuf;
1675 h->fsize = cw->fsize;
1685 fprint(2, "%lld blocks queued for worm\n", (Wideoff)cw->ndump);
1686 fprint(2, "%lld falsehits\n", (Wideoff)cw->falsehits);
1691 * extend all of the locks
1693 tim = toytime() - tim;
1694 for(i=0; i<NTLOCK; i++)
1695 if(tlocks[i].time > 0)
1696 tlocks[i].time += tim;
1699 nextdump(time(nil));
1707 mvstates(Device *dev, int s1, int s2, int side)
1713 Off m, lo, hi, msize, maddr;
1718 hi = lo + devsize(dev->cw.w); /* size of all sides totalled */
1720 /* operate on only a single disc side */
1723 wormsidestarts(dev, side, &ss);
1727 cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
1728 if(!cb || checktag(cb, Tcache, QPSUPER))
1729 panic("mvstates: checktag super");
1730 h = (Cache*)cb->iobuf;
1735 for(m=0; m<msize; m++) {
1736 p = getbuf(cw->cdev, maddr + m/BKPERBLK, Brd|Bmod);
1737 if(!p || checktag(p, Tbuck, maddr + m/BKPERBLK))
1738 panic("mvstates: checktag c bucket");
1739 b = (Bucket*)p->iobuf + m%BKPERBLK;
1740 ce = b->entry + CEPERBK;
1741 for(c=b->entry; c<ce; c++)
1742 if(c->state == s1 && c->waddr >= lo && c->waddr < hi)
1749 prchain(Device *dev, Off m, int flg)
1758 m = getstartsb(dev);
1760 p = getbuf(devnone, Cwxx2, 0);
1761 s = (Superb*)p->iobuf;
1763 memset(p->iobuf, 0, RBUFSIZE);
1764 if(devread(WDEV(dev), m, p->iobuf) ||
1765 checktag(p, Tsuper, QPSUPER))
1768 print("dump %lld is good; %lld prev\n", (Wideoff)m,
1770 print("\t%lld cwroot; %lld roroot\n",
1771 (Wideoff)s->cwraddr, (Wideoff)s->roraddr);
1776 print("dump %lld is good; %lld next\n", (Wideoff)m,
1778 print("\t%lld cwroot; %lld roroot\n",
1779 (Wideoff)s->cwraddr, (Wideoff)s->roraddr);
1789 touchsb(Device *dev)
1795 p = getbuf(devnone, Cwxx2, 0);
1797 memset(p->iobuf, 0, RBUFSIZE);
1798 if(devread(WDEV(dev), m, p->iobuf) ||
1799 checktag(p, Tsuper, QPSUPER))
1800 fprint(2, "%Z block %lld WORM SUPER BLOCK READ FAILED\n",
1801 WDEV(dev), (Wideoff)m);
1803 print("%Z touch superblock %lld\n", WDEV(dev), (Wideoff)m);
1808 storesb(Device *dev, Off last, int doit)
1815 sbaddr = cwsaddr(dev);
1817 ps = getbuf(devnone, Cwxx2, 0);
1819 fprint(2, "storesb: getbuf\n");
1824 * try to read last sb
1826 memset(ps->iobuf, 0, RBUFSIZE);
1827 if(devread(WDEV(dev), last, ps->iobuf) ||
1828 checktag(ps, Tsuper, QPSUPER))
1829 print("read last failed\n");
1831 print("read last succeeded\n");
1833 s = (Superb*)ps->iobuf;
1838 if(s->next != sbaddr)
1839 print("next(last) is not sbaddr %lld %lld\n",
1840 (Wideoff)s->next, (Wideoff)sbaddr);
1842 print("next(last) is sbaddr\n");
1845 * read cached superblock
1847 ph = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
1848 if(!ph || checktag(ph, Tcache, QPSUPER)) {
1849 print("storesb: checktag super\n");
1855 print("read cached sb succeeded\n");
1857 h = (Cache*)ph->iobuf;
1859 memset(ps->iobuf, 0, RBUFSIZE);
1860 settag(ps, Tsuper, QPSUPER);
1862 s = (Superb*)ps->iobuf;
1864 s->cwraddr = h->cwraddr;
1865 s->roraddr = h->roraddr;
1866 s->fsize = h->fsize;
1869 s->next = h->roraddr+1;
1874 if(s->fsize-1 != s->next ||
1875 s->fsize-2 != s->roraddr ||
1876 s->fsize-5 != s->cwraddr) {
1877 print("addrs not in relationship %lld %lld %lld %lld\n",
1878 (Wideoff)s->cwraddr, (Wideoff)s->roraddr,
1879 (Wideoff)s->next, (Wideoff)s->fsize);
1883 print("addresses in relation\n");
1886 if(devwrite(WDEV(dev), sbaddr, ps->iobuf))
1887 print("%Z block %lld WORM SUPER BLOCK WRITE FAILED\n",
1888 WDEV(dev), (Wideoff)sbaddr);
1894 savecache(Device *dev)
1901 Off m, maddr, msize, *longp, nbyte;
1904 if(walkto("/adm/cache") || con_open(FID2, OWRITE|OTRUNC)) {
1905 fprint(2, "cant open /adm/cache\n");
1909 cb = getbuf(cdev, CACHE_ADDR, Brd|Bres);
1910 if(!cb || checktag(cb, Tcache, QPSUPER))
1911 panic("savecache: checktag super");
1912 h = (Cache*)cb->iobuf;
1917 n = BUFSIZE; /* calculate write size */
1921 cb = getbuf(devnone, Cwxx4, 0);
1922 longp = (Off *)cb->iobuf;
1923 left = n/sizeof(Off);
1926 for(m=0; m<msize; m++) {
1927 if(left < BKPERBLK) {
1928 nbyte = (n/sizeof(Off) - left) * sizeof(Off);
1929 con_write(FID2, cb->iobuf, cons.offset, nbyte);
1930 cons.offset += nbyte;
1931 longp = (Off *)cb->iobuf;
1932 left = n/sizeof(Off);
1934 p = getbuf(cdev, maddr + m/BKPERBLK, Brd);
1935 if(!p || checktag(p, Tbuck, maddr + m/BKPERBLK))
1936 panic("savecache: checktag c bucket");
1937 b = (Bucket*)p->iobuf + m%BKPERBLK;
1938 ce = b->entry + CEPERBK;
1939 for(c = b->entry; c < ce; c++)
1940 if(c->state == Cread) {
1941 *longp++ = c->waddr;
1946 nbyte = (n/sizeof(Off) - left) * sizeof(Off);
1947 con_write(FID2, cb->iobuf, cons.offset, nbyte);
1952 loadcache(Device *dev, int dskno)
1955 Off m, nbyte, *longp, count;
1958 if(walkto("/adm/cache") || con_open(FID2, OREAD)) {
1959 fprint(2, "cant open /adm/cache\n");
1963 cb = getbuf(devnone, Cwxx4, 0);
1968 wormsidestarts(dev, dskno, &ss);
1970 memset(cb->iobuf, 0, BUFSIZE);
1971 nbyte = con_read(FID2, cb->iobuf, cons.offset, 100) / sizeof(Off);
1974 cons.offset += nbyte * sizeof(Off);
1975 longp = (Off *)cb->iobuf;
1981 /* if given a diskno, restrict to just that disc side */
1982 if(dskno < 0 || m >= ss.sstart && m < ss.s1start) {
1983 p = getbuf(dev, m, Brd);
1991 print("%lld blocks loaded from worm %d\n", (Wideoff)count, dskno);
1995 morecache(Device *dev, int dskno, Off size)
1998 Off m, ml, mh, mm, count;
2002 p = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
2003 if(!p || checktag(p, Tcache, QPSUPER))
2004 panic("morecache: checktag super");
2005 h = (Cache*)p->iobuf;
2009 wormsidestarts(dev, dskno, &ss);
2010 ml = ss.sstart; /* start at beginning of disc side #dskno */
2014 print("limited to %lld\n", (Wideoff)mh-ml);
2018 for(m=ml; m < mh; m++) {
2019 p = getbuf(dev, m, Brd);
2024 print("%lld blocks loaded from worm %d\n", (Wideoff)count, dskno);
2028 blockcmp(Device *dev, Off wa, Off ca)
2033 p1 = getbuf(WDEV(dev), wa, Brd);
2035 fprint(2, "blockcmp: wdev error\n");
2039 p2 = getbuf(CDEV(dev), ca, Brd);
2041 fprint(2, "blockcmp: cdev error\n");
2047 for(i=0; i<RBUFSIZE; i++)
2048 if(p1->iobuf[i] != p2->iobuf[i]) {
2049 print("%4d: %.2x %.2x\n",
2063 wblock(Device *dev, Off addr)
2068 p1 = getbuf(dev, addr, Brd);
2070 i = devwrite(WDEV(dev), addr, p1->iobuf);
2071 print("i = %d\n", i);
2082 /* garbage to change sb size
2083 * probably will need it someday
2085 fsz = number(0, 0, 10);
2087 if(fsz == number(0, -1, 10))
2088 count = -1; /* really do it */
2089 print("fsize = %ld\n", fsz);
2091 cb = getbuf(cdev, CACHE_ADDR, Brd|Bres);
2092 if(!cb || checktag(cb, Tcache, QPSUPER))
2093 panic("cwtest: checktag super");
2094 h = (Cache*)cb->iobuf;
2095 for(m=0; m<h->msize; m++) {
2096 p = getbuf(cdev, h->maddr + m/BKPERBLK, Brd|Bmod);
2097 if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK))
2098 panic("cwtest: checktag c bucket");
2099 b = (Bucket*)p->iobuf + m%BKPERBLK;
2100 ce = b->entry + CEPERBK;
2101 for(c=b->entry; c<ce; c++) {
2108 if(c->state != Cdirty)
2114 print("old cache hsize = %ld\n", h->fsize);
2117 p = getbuf(dev, h->sbaddr, Brd|Bmod);
2118 s = (Superb*)p->iobuf;
2119 print("old super hsize = %ld\n", s->fsize);
2124 print("count = %lld\n", (Wideoff)count);
2128 convstate(char *name)
2132 for(i=0; i<nelem(cwnames); i++)
2134 if(strcmp(cwnames[i], name) == 0)
2140 searchtag(Device *d, Off a, int tag, int n)
2148 p = getbuf(devnone, Cwxx2, 0);
2149 t = (Tag*)(p->iobuf+BUFSIZE);
2150 for(i=0; i<n; i++) {
2151 memset(p->iobuf, 0, RBUFSIZE);
2152 if(devread(WDEV(d), a+i, p->iobuf)) {
2158 print("tag %d found at %Z %lld\n", tag, d, (Wideoff)a+i);
2166 cmd_cwcmd(int argc, char *argv[])
2171 Off s1, s2, a, b, n;
2175 print("\tcwcmd mvstate state1 state2 [platter]\n");
2176 print("\tcwcmd prchain [start] [bakflg]\n");
2177 print("\tcwcmd searchtag [start] [tag] [blocks]\n");
2178 print("\tcwcmd touchsb\n");
2179 print("\tcwcmd savecache\n");
2180 print("\tcwcmd loadcache [dskno]\n");
2181 print("\tcwcmd morecache dskno [count]\n");
2182 print("\tcwcmd blockcmp wbno cbno\n");
2183 print("\tcwcmd startdump [01]\n");
2184 print("\tcwcmd acct\n");
2185 print("\tcwcmd clearacct\n");
2191 * items not depend on a cw filesystem
2193 if(strcmp(arg, "acct") == 0) {
2194 for(a=0; a<nelem(growacct); a++) {
2197 uidtostr(str, a, 1);
2198 print("%10lld %s\n",
2199 ((Wideoff)b*ADDFREE*RBUFSIZE+500000)/1000000,
2205 if(strcmp(arg, "clearacct") == 0) {
2206 memset(growacct, 0, sizeof(growacct));
2211 * items depend on cw filesystem
2213 dev = cons.curfs->dev;
2214 if(dev == 0 || dev->type != Devcw || dev->private == 0) {
2215 print("cfs not a cw filesystem: %Z\n", dev);
2219 if(strcmp(arg, "searchtag") == 0) {
2222 a = number(argv[2], 0, 10);
2225 b = number(argv[3], 0, 10);
2228 n = number(argv[4], 0, 10);
2229 searchtag(dev, a, b, n);
2230 } else if(strcmp(arg, "mvstate") == 0) {
2233 s1 = convstate(argv[2]);
2234 s2 = convstate(argv[3]);
2235 if(s1 < 0 || s2 < 0)
2239 a = number(argv[4], 0, 10);
2240 mvstates(dev, s1, s2, a);
2243 print("cwcmd mvstate: bad args\n");
2244 } else if(strcmp(arg, "prchain") == 0) {
2247 a = number(argv[2], 0, 10);
2250 s1 = number(argv[3], 0, 10);
2251 prchain(dev, a, s1);
2252 } else if(strcmp(arg, "touchsb") == 0)
2254 else if(strcmp(arg, "savecache") == 0)
2256 else if(strcmp(arg, "loadcache") == 0) {
2259 s1 = number(argv[2], 0, 10);
2261 } else if(strcmp(arg, "morecache") == 0) {
2263 print("arg count\n");
2266 s1 = number(argv[2], 0, 10);
2268 s2 = number(argv[3], 0, 10);
2270 s2 = wormsizeside(dev, s1); /* default to 1 disc side */
2271 morecache(dev, s1, s2);
2272 } else if(strcmp(arg, "blockcmp") == 0) {
2274 print("cannot arg count\n");
2277 s1 = number(argv[2], 0, 10);
2278 s2 = number(argv[3], 0, 10);
2279 blockcmp(dev, s1, s2);
2280 } else if(strcmp(arg, "startdump") == 0) {
2282 cw->nodump = number(argv[2], 0, 10);
2284 cw->nodump = !cw->nodump;
2286 print("dump stopped\n");
2288 print("dump allowed\n");
2289 } else if(strcmp(arg, "allflag") == 0) {
2291 cw->allflag = number(argv[2], 0, 10);
2293 cw->allflag = !cw->allflag;
2294 print("allflag = %d; falsehits = %lld\n",
2295 cw->allflag, (Wideoff)cw->falsehits);
2296 } else if(strcmp(arg, "storesb") == 0) {
2300 a = number(argv[2], 4168344, 10);
2302 b = number(argv[3], 0, 10);
2304 } else if(strcmp(arg, "test") == 0)
2307 print("unknown cwcmd %s\n", arg);