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
cmd_dump(int argc,char * argv[])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
cmd_statw(int,char * [])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
dumpblock(Device * dev)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
cwinit1(Device * dev)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
cwinit(Device * dev)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
cwsaddr(Device * dev)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
cwraddr(Device * dev)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
cwsize(Device * dev)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
cwread(Device * dev,Off b,void * c)497 cwread(Device *dev, Off b, void *c)
498 {
499 return cwio(dev, b, c, Oread) == Cerror;
500 }
501
502 int
cwwrite(Device * dev,Off b,void * c)503 cwwrite(Device *dev, Off b, void *c)
504 {
505 return cwio(dev, b, c, Owrite) == Cerror;
506 }
507
508 int
roread(Device * dev,Off b,void * c)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
cwio(Device * dev,Off addr,void * buf,int opcode)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
cwgrow(Device * dev,Superb * sb,int uid)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
cwfree(Device * dev,Off addr)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
bktcheck(Bucket * b)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
resequence(Bucket * b)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*
getcentry(Bucket * b,Off addr)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*
cacheinit(Device * dev)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
getstartsb(Device * dev)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
cwrecover(Device * dev)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
cwream(Device * dev)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
rewalk1(Cw * cw,Off addr,int slot,Wpath * up)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
rewalk2(Cw * cw,Off addr,int slot,Wpath * up)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
rewalk(Cw * cw)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
split(Cw * cw,Iobuf * p,Off addr)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
isdirty(Cw * cw,Iobuf * p,Off addr,int tag)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
cwrecur(Cw * cw,Off addr,int tag,int tag1,long qp)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
cfsdump(Filsys * fs)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
mvstates(Device * dev,int s1,int s2,int side)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
prchain(Device * dev,Off m,int flg)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
touchsb(Device * dev)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
storesb(Device * dev,Off last,int doit)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
savecache(Device * dev)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
loadcache(Device * dev,int dskno)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
morecache(Device * dev,int dskno,Off size)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
blockcmp(Device * dev,Off wa,Off ca)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
wblock(Device * dev,Off addr)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
cwtest(Device *)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
convstate(char * name)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
searchtag(Device * d,Off a,int tag,int n)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
cmd_cwcmd(int argc,char * argv[])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