xref: /plan9/sys/src/cmd/cwfs/cw.c (revision e6d20ddfa7d12e75efbb79fca45df9e14315b5f6)
101a344a2SDavid du Colombier /*
201a344a2SDavid du Colombier  * cached-worm device
301a344a2SDavid du Colombier  */
401a344a2SDavid du Colombier #include "all.h"
501a344a2SDavid du Colombier 
601a344a2SDavid du Colombier #define	CDEV(d)		((d)->cw.c)
701a344a2SDavid du Colombier #define	WDEV(d)		((d)->cw.w)
801a344a2SDavid du Colombier #define	RDEV(d)		((d)->cw.ro)
901a344a2SDavid du Colombier 
1001a344a2SDavid du Colombier enum {
1101a344a2SDavid du Colombier 	DEBUG		= 0,
1201a344a2SDavid du Colombier 	FIRST		= SUPER_ADDR,
1301a344a2SDavid du Colombier 
1401a344a2SDavid du Colombier 	ADDFREE		= 100,
1501a344a2SDavid du Colombier 	CACHE_ADDR	= SUPER_ADDR,
1601a344a2SDavid du Colombier 	MAXAGE		= 10000,
1701a344a2SDavid du Colombier };
1801a344a2SDavid du Colombier 
1901a344a2SDavid du Colombier /* cache state */
2001a344a2SDavid du Colombier enum
2101a344a2SDavid du Colombier {
2201a344a2SDavid du Colombier 	/* states -- beware these are recorded on the cache */
2301a344a2SDavid du Colombier 				/*    cache    worm	*/
2401a344a2SDavid du Colombier 	Cnone = 0,		/*	0	?	*/
2501a344a2SDavid du Colombier 	Cdirty,			/*	1	0	*/
2601a344a2SDavid du Colombier 	Cdump,			/*	1	0->1	*/
2701a344a2SDavid du Colombier 	Cread,			/*	1	1	*/
2801a344a2SDavid du Colombier 	Cwrite,			/*	2	1	*/
2901a344a2SDavid du Colombier 	Cdump1,			/* inactive form of dump */
3001a344a2SDavid du Colombier 	Cerror,
3101a344a2SDavid du Colombier 
3201a344a2SDavid du Colombier 	/* opcodes -- these are not recorded */
3301a344a2SDavid du Colombier 	Onone,
3401a344a2SDavid du Colombier 	Oread,
3501a344a2SDavid du Colombier 	Owrite,
3601a344a2SDavid du Colombier 	Ogrow,
3701a344a2SDavid du Colombier 	Odump,
3801a344a2SDavid du Colombier 	Orele,
3901a344a2SDavid du Colombier 	Ofree,
4001a344a2SDavid du Colombier };
4101a344a2SDavid du Colombier 
4201a344a2SDavid du Colombier typedef	struct	Cw	Cw;
4301a344a2SDavid du Colombier struct	Cw
4401a344a2SDavid du Colombier {
4501a344a2SDavid du Colombier 	Device*	dev;
4601a344a2SDavid du Colombier 	Device*	cdev;
4701a344a2SDavid du Colombier 	Device*	wdev;
4801a344a2SDavid du Colombier 	Device*	rodev;
4901a344a2SDavid du Colombier 	Cw*	link;
5001a344a2SDavid du Colombier 
5101a344a2SDavid du Colombier 	int	dbucket;	/* last bucket dumped */
5201a344a2SDavid du Colombier 	Off	daddr;		/* last block dumped */
5301a344a2SDavid du Colombier 	Off	ncopy;
5401a344a2SDavid du Colombier 	int	nodump;
5501a344a2SDavid du Colombier /*
5601a344a2SDavid du Colombier  * following are cached variables for dumps
5701a344a2SDavid du Colombier  */
5801a344a2SDavid du Colombier 	Off	fsize;
5901a344a2SDavid du Colombier 	Off	ndump;
6001a344a2SDavid du Colombier 	int	depth;
6101a344a2SDavid du Colombier 	int	all;		/* local flag to recur on modified dirs */
6201a344a2SDavid du Colombier 	int	allflag;	/* global flag to recur on modified dirs */
6301a344a2SDavid du Colombier 	Off	falsehits;	/* times recur found modified blocks */
6401a344a2SDavid du Colombier 	struct {
6501a344a2SDavid du Colombier 		char	name[500];
6601a344a2SDavid du Colombier 		char	namepad[NAMELEN+10];
6701a344a2SDavid du Colombier 	};
6801a344a2SDavid du Colombier };
6901a344a2SDavid du Colombier 
7001a344a2SDavid du Colombier static char* cwnames[] =
7101a344a2SDavid du Colombier {
7201a344a2SDavid du Colombier 	[Cnone]		"none",
7301a344a2SDavid du Colombier 	[Cdirty]	"dirty",
7401a344a2SDavid du Colombier 	[Cdump]		"dump",
7501a344a2SDavid du Colombier 	[Cread]		"read",
7601a344a2SDavid du Colombier 	[Cwrite]	"write",
7701a344a2SDavid du Colombier 	[Cdump1]	"dump1",
7801a344a2SDavid du Colombier 	[Cerror]	"error",
7901a344a2SDavid du Colombier 
8001a344a2SDavid du Colombier 	[Onone]		"none",
8101a344a2SDavid du Colombier 	[Oread]		"read",
8201a344a2SDavid du Colombier 	[Owrite]	"write",
8301a344a2SDavid du Colombier 	[Ogrow]		"grow",
8401a344a2SDavid du Colombier 	[Odump]		"dump",
8501a344a2SDavid du Colombier 	[Orele]		"rele",
8601a344a2SDavid du Colombier };
8701a344a2SDavid du Colombier 
88698b102bSDavid du Colombier int oldcachefmt = 1;
89698b102bSDavid du Colombier 
9001a344a2SDavid du Colombier Centry*	getcentry(Bucket*, Off);
9101a344a2SDavid du Colombier int	cwio(Device*, Off, void*, int);
9201a344a2SDavid du Colombier void	cmd_cwcmd(int, char*[]);
9301a344a2SDavid du Colombier 
9401a344a2SDavid du Colombier /*
9501a344a2SDavid du Colombier  * console command
9601a344a2SDavid du Colombier  * initiate a dump
9701a344a2SDavid du Colombier  */
9801a344a2SDavid du Colombier void
cmd_dump(int argc,char * argv[])9901a344a2SDavid du Colombier cmd_dump(int argc, char *argv[])
10001a344a2SDavid du Colombier {
10101a344a2SDavid du Colombier 	Filsys *fs;
10201a344a2SDavid du Colombier 
10301a344a2SDavid du Colombier 	fs = cons.curfs;
10401a344a2SDavid du Colombier 	if(argc > 1)
10501a344a2SDavid du Colombier 		fs = fsstr(argv[1]);
10601a344a2SDavid du Colombier 	if(fs == 0) {
10701a344a2SDavid du Colombier 		print("%s: unknown file system\n", argv[1]);
10801a344a2SDavid du Colombier 		return;
10901a344a2SDavid du Colombier 	}
11001a344a2SDavid du Colombier 	cfsdump(fs);
11101a344a2SDavid du Colombier }
11201a344a2SDavid du Colombier 
11301a344a2SDavid du Colombier /*
11401a344a2SDavid du Colombier  * console command
11501a344a2SDavid du Colombier  * worm stats
11601a344a2SDavid du Colombier  */
11701a344a2SDavid du Colombier static void
cmd_statw(int,char * [])11801a344a2SDavid du Colombier cmd_statw(int, char*[])
11901a344a2SDavid du Colombier {
12001a344a2SDavid du Colombier 	Filsys *fs;
12101a344a2SDavid du Colombier 	Iobuf *p;
12201a344a2SDavid du Colombier 	Superb *sb;
12301a344a2SDavid du Colombier 	Cache *h;
12401a344a2SDavid du Colombier 	Bucket *b;
12501a344a2SDavid du Colombier 	Centry *c, *ce;
12601a344a2SDavid du Colombier 	Off m, nw, bw, state[Onone];
12701a344a2SDavid du Colombier 	Off sbfsize, sbcwraddr, sbroraddr, sblast, sbnext;
12801a344a2SDavid du Colombier 	Off hmsize, hmaddr, dsize, dsizepct;
12901a344a2SDavid du Colombier 	Device *dev;
13001a344a2SDavid du Colombier 	Cw *cw;
13101a344a2SDavid du Colombier 	int s;
13201a344a2SDavid du Colombier 
13301a344a2SDavid du Colombier 	fs = cons.curfs;
13401a344a2SDavid du Colombier 	dev = fs->dev;
13501a344a2SDavid du Colombier 	if(dev->type != Devcw) {
13601a344a2SDavid du Colombier 		print("curfs not type cw\n");
13701a344a2SDavid du Colombier 		return;
13801a344a2SDavid du Colombier 	}
13901a344a2SDavid du Colombier 
14001a344a2SDavid du Colombier 	cw = dev->private;
14101a344a2SDavid du Colombier 	if(cw == 0) {
14201a344a2SDavid du Colombier 		print("curfs not inited\n");
14301a344a2SDavid du Colombier 		return;
14401a344a2SDavid du Colombier 	}
14501a344a2SDavid du Colombier 
14601a344a2SDavid du Colombier 	print("cwstats %s\n", fs->name);
14701a344a2SDavid du Colombier 
14801a344a2SDavid du Colombier 	sbfsize = 0;
14901a344a2SDavid du Colombier 	sbcwraddr = 0;
15001a344a2SDavid du Colombier 	sbroraddr = 0;
15101a344a2SDavid du Colombier 	sblast = 0;
15201a344a2SDavid du Colombier 	sbnext = 0;
15301a344a2SDavid du Colombier 
15401a344a2SDavid du Colombier 	print("\tfilesys %s\n", fs->name);
15501a344a2SDavid du Colombier //	print("\tnio   =%7W%7W%7W\n", cw->ncwio+0, cw->ncwio+1, cw->ncwio+2);
15601a344a2SDavid du Colombier 	p = getbuf(dev, cwsaddr(dev), Brd);
15701a344a2SDavid du Colombier 	if(!p || checktag(p, Tsuper, QPSUPER)) {
15801a344a2SDavid du Colombier 		print("cwstats: checktag super\n");
15901a344a2SDavid du Colombier 		if(p) {
16001a344a2SDavid du Colombier 			putbuf(p);
16101a344a2SDavid du Colombier 			p = 0;
16201a344a2SDavid du Colombier 		}
16301a344a2SDavid du Colombier 	}
16401a344a2SDavid du Colombier 	if(p) {
16501a344a2SDavid du Colombier 		sb = (Superb*)p->iobuf;
16601a344a2SDavid du Colombier 		sbfsize = sb->fsize;
16701a344a2SDavid du Colombier 		sbcwraddr = sb->cwraddr;
16801a344a2SDavid du Colombier 		sbroraddr = sb->roraddr;
16901a344a2SDavid du Colombier 		sblast = sb->last;
17001a344a2SDavid du Colombier 		sbnext = sb->next;
17101a344a2SDavid du Colombier 		putbuf(p);
17201a344a2SDavid du Colombier 	}
17301a344a2SDavid du Colombier 
17401a344a2SDavid du Colombier 	p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
17501a344a2SDavid du Colombier 	if(!p || checktag(p, Tcache, QPSUPER)) {
17601a344a2SDavid du Colombier 		print("cwstats: checktag c bucket\n");
17701a344a2SDavid du Colombier 		if(p)
17801a344a2SDavid du Colombier 			putbuf(p);
17901a344a2SDavid du Colombier 		return;
18001a344a2SDavid du Colombier 	}
18101a344a2SDavid du Colombier 	h = (Cache*)p->iobuf;
18201a344a2SDavid du Colombier 	hmaddr = h->maddr;
18301a344a2SDavid du Colombier 	hmsize = h->msize;
18401a344a2SDavid du Colombier 
18501a344a2SDavid du Colombier 	print("\t\tmaddr  = %8lld\n", (Wideoff)hmaddr);
18601a344a2SDavid du Colombier 	print("\t\tmsize  = %8lld\n", (Wideoff)hmsize);
18701a344a2SDavid du Colombier 	print("\t\tcaddr  = %8lld\n", (Wideoff)h->caddr);
18801a344a2SDavid du Colombier 	print("\t\tcsize  = %8lld\n", (Wideoff)h->csize);
18901a344a2SDavid du Colombier 	print("\t\tsbaddr = %8lld\n", (Wideoff)h->sbaddr);
19001a344a2SDavid du Colombier 	print("\t\tcraddr = %8lld %8lld\n",
19101a344a2SDavid du Colombier 		(Wideoff)h->cwraddr, (Wideoff)sbcwraddr);
19201a344a2SDavid du Colombier 	print("\t\troaddr = %8lld %8lld\n",
19301a344a2SDavid du Colombier 		(Wideoff)h->roraddr, (Wideoff)sbroraddr);
19401a344a2SDavid du Colombier 	/* print stats in terms of (first-)disc sides */
19501a344a2SDavid du Colombier 	dsize = wormsizeside(dev, 0);
19601a344a2SDavid du Colombier 	if (dsize < 1) {
19701a344a2SDavid du Colombier 		if (DEBUG)
19801a344a2SDavid du Colombier 			print("wormsizeside returned size %lld for %Z side 0\n",
19901a344a2SDavid du Colombier 				(Wideoff)dsize, dev);
20001a344a2SDavid du Colombier 		dsize = h->wsize;	/* it's probably a fake worm */
20101a344a2SDavid du Colombier 		if (dsize < 1)
20201a344a2SDavid du Colombier 			dsize = 1000;	/* don't divide by zero */
20301a344a2SDavid du Colombier 	}
20401a344a2SDavid du Colombier 	dsizepct = dsize/100;
20501a344a2SDavid du Colombier 	print("\t\tfsize  = %8lld %8lld %2lld+%2lld%%\n", (Wideoff)h->fsize,
20601a344a2SDavid du Colombier 		(Wideoff)sbfsize, (Wideoff)h->fsize/dsize,
20701a344a2SDavid du Colombier 		(Wideoff)(h->fsize%dsize)/dsizepct);
20801a344a2SDavid du Colombier 	print("\t\tslast  =          %8lld\n", (Wideoff)sblast);
20901a344a2SDavid du Colombier 	print("\t\tsnext  =          %8lld\n", (Wideoff)sbnext);
21001a344a2SDavid du Colombier 	print("\t\twmax   = %8lld          %2lld+%2lld%%\n",
21101a344a2SDavid du Colombier 		(Wideoff)h->wmax, (Wideoff)h->wmax/dsize,
21201a344a2SDavid du Colombier 		(Wideoff)(h->wmax%dsize)/dsizepct);
21301a344a2SDavid du Colombier 	print("\t\twsize  = %8lld          %2lld+%2lld%%\n",
21401a344a2SDavid du Colombier 		(Wideoff)h->wsize, (Wideoff)h->wsize/dsize,
21501a344a2SDavid du Colombier 		(Wideoff)(h->wsize%dsize)/dsizepct);
21601a344a2SDavid du Colombier 	putbuf(p);
21701a344a2SDavid du Colombier 
21801a344a2SDavid du Colombier 	bw = 0;			/* max filled bucket */
21901a344a2SDavid du Colombier 	memset(state, 0, sizeof(state));
22001a344a2SDavid du Colombier 	for(m = 0; m < hmsize; m++) {
22101a344a2SDavid du Colombier 		p = getbuf(cw->cdev, hmaddr + m/BKPERBLK, Brd);
22201a344a2SDavid du Colombier 		if(!p || checktag(p, Tbuck, hmaddr + m/BKPERBLK)) {
22301a344a2SDavid du Colombier 			print("cwstats: checktag c bucket\n");
22401a344a2SDavid du Colombier 			if(p)
22501a344a2SDavid du Colombier 				putbuf(p);
22601a344a2SDavid du Colombier 			return;
22701a344a2SDavid du Colombier 		}
22801a344a2SDavid du Colombier 		b = (Bucket*)p->iobuf + m%BKPERBLK;
22901a344a2SDavid du Colombier 		ce = b->entry + CEPERBK;
23001a344a2SDavid du Colombier 		nw = 0;
23101a344a2SDavid du Colombier 		for(c = b->entry; c < ce; c++) {
23201a344a2SDavid du Colombier 			s = c->state;
23301a344a2SDavid du Colombier 			state[s]++;
23401a344a2SDavid du Colombier 			if(s != Cnone && s != Cread)
23501a344a2SDavid du Colombier 				nw++;
23601a344a2SDavid du Colombier 		}
23701a344a2SDavid du Colombier 		putbuf(p);
23801a344a2SDavid du Colombier 		if(nw > bw)
23901a344a2SDavid du Colombier 			bw = nw;
24001a344a2SDavid du Colombier 	}
24101a344a2SDavid du Colombier 	for(s = Cnone; s < Cerror; s++)
24201a344a2SDavid du Colombier 		print("\t\t%6lld %s\n", (Wideoff)state[s], cwnames[s]);
24301a344a2SDavid du Colombier 	print("\t\tcache %2lld%% full\n", ((Wideoff)bw*100)/CEPERBK);
24401a344a2SDavid du Colombier }
24501a344a2SDavid du Colombier 
24601a344a2SDavid du Colombier int
dumpblock(Device * dev)24701a344a2SDavid du Colombier dumpblock(Device *dev)
24801a344a2SDavid du Colombier {
24901a344a2SDavid du Colombier 	Iobuf *p, *cb, *p1, *p2;
25001a344a2SDavid du Colombier 	Cache *h;
25101a344a2SDavid du Colombier 	Centry *c, *ce, *bc;
25201a344a2SDavid du Colombier 	Bucket *b;
25301a344a2SDavid du Colombier 	Off m, a, msize, maddr, wmax, caddr;
25401a344a2SDavid du Colombier 	int s1, s2, count;
25501a344a2SDavid du Colombier 	Cw *cw;
25601a344a2SDavid du Colombier 
25701a344a2SDavid du Colombier 	cw = dev->private;
25801a344a2SDavid du Colombier 	if(cw == 0 || cw->nodump)
25901a344a2SDavid du Colombier 		return 0;
26001a344a2SDavid du Colombier 
26101a344a2SDavid du Colombier 	cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
26201a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
26301a344a2SDavid du Colombier 	msize = h->msize;
26401a344a2SDavid du Colombier 	maddr = h->maddr;
26501a344a2SDavid du Colombier 	wmax = h->wmax;
26601a344a2SDavid du Colombier 	caddr = h->caddr;
26701a344a2SDavid du Colombier 	putbuf(cb);
26801a344a2SDavid du Colombier 
26901a344a2SDavid du Colombier 	for(m=msize; m>=0; m--) {
27001a344a2SDavid du Colombier 		a = cw->dbucket + 1;
27101a344a2SDavid du Colombier 		if(a < 0 || a >= msize)
27201a344a2SDavid du Colombier 			a = 0;
27301a344a2SDavid du Colombier 		cw->dbucket = a;
27401a344a2SDavid du Colombier 		p = getbuf(cw->cdev, maddr + a/BKPERBLK, Brd);
27501a344a2SDavid du Colombier 		b = (Bucket*)p->iobuf + a%BKPERBLK;
27601a344a2SDavid du Colombier 		ce = b->entry + CEPERBK;
27701a344a2SDavid du Colombier 		bc = 0;
27801a344a2SDavid du Colombier 		for(c = b->entry; c < ce; c++)
27901a344a2SDavid du Colombier 			if(c->state == Cdump) {
28001a344a2SDavid du Colombier 				if(bc == 0) {
28101a344a2SDavid du Colombier 					bc = c;
28201a344a2SDavid du Colombier 					continue;
28301a344a2SDavid du Colombier 				}
28401a344a2SDavid du Colombier 				if(c->waddr < cw->daddr) {
28501a344a2SDavid du Colombier 					if(bc->waddr < cw->daddr &&
28601a344a2SDavid du Colombier 					   bc->waddr > c->waddr)
28701a344a2SDavid du Colombier 						bc = c;
28801a344a2SDavid du Colombier 					continue;
28901a344a2SDavid du Colombier 				}
29001a344a2SDavid du Colombier 				if(bc->waddr < cw->daddr ||
29101a344a2SDavid du Colombier 				   bc->waddr > c->waddr)
29201a344a2SDavid du Colombier 					bc = c;
29301a344a2SDavid du Colombier 			}
29401a344a2SDavid du Colombier 		if(bc) {
29501a344a2SDavid du Colombier 			c = bc;
29601a344a2SDavid du Colombier 			goto found;
29701a344a2SDavid du Colombier 		}
29801a344a2SDavid du Colombier 		putbuf(p);
29901a344a2SDavid du Colombier 	}
30001a344a2SDavid du Colombier 	if(cw->ncopy) {
30101a344a2SDavid du Colombier 		print("%lld blocks copied to worm\n", (Wideoff)cw->ncopy);
30201a344a2SDavid du Colombier 		cw->ncopy = 0;
30301a344a2SDavid du Colombier 	}
30401a344a2SDavid du Colombier 	cw->nodump = 1;
30501a344a2SDavid du Colombier 	return 0;
30601a344a2SDavid du Colombier 
30701a344a2SDavid du Colombier found:
308698b102bSDavid du Colombier 	if (oldcachefmt)
30901a344a2SDavid du Colombier 		a = a*CEPERBK + (c - b->entry) + caddr;
310698b102bSDavid du Colombier 	else
311698b102bSDavid du Colombier 		a += (c - b->entry)*msize + caddr;
31201a344a2SDavid du Colombier 	p1 = getbuf(devnone, Cwdump1, 0);
31301a344a2SDavid du Colombier 	count = 0;
31401a344a2SDavid du Colombier 
31501a344a2SDavid du Colombier retry:
31601a344a2SDavid du Colombier 	count++;
317698b102bSDavid du Colombier 	if(count > 10 || devread(cw->cdev, a, p1->iobuf))
31801a344a2SDavid du Colombier 		goto stop;
31901a344a2SDavid du Colombier 	m = c->waddr;
32001a344a2SDavid du Colombier 	cw->daddr = m;
32101a344a2SDavid du Colombier 	s1 = devwrite(cw->wdev, m, p1->iobuf);
32201a344a2SDavid du Colombier 	if(s1) {
32301a344a2SDavid du Colombier 		p2 = getbuf(devnone, Cwdump2, 0);
32401a344a2SDavid du Colombier 		s2 = devread(cw->wdev, m, p2->iobuf);
32501a344a2SDavid du Colombier 		if(s2) {
32601a344a2SDavid du Colombier 			if(s1 == 0x61 && s2 == 0x60) {
32701a344a2SDavid du Colombier 				putbuf(p2);
32801a344a2SDavid du Colombier 				goto retry;
32901a344a2SDavid du Colombier 			}
33001a344a2SDavid du Colombier 			goto stop1;
33101a344a2SDavid du Colombier 		}
33201a344a2SDavid du Colombier 		if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE))
33301a344a2SDavid du Colombier 			goto stop1;
33401a344a2SDavid du Colombier 		putbuf(p2);
33501a344a2SDavid du Colombier 	}
33601a344a2SDavid du Colombier 	/*
33701a344a2SDavid du Colombier 	 * reread and compare
33801a344a2SDavid du Colombier 	 */
33901a344a2SDavid du Colombier 	if(conf.dumpreread) {
34001a344a2SDavid du Colombier 		p2 = getbuf(devnone, Cwdump2, 0);
34101a344a2SDavid du Colombier 		s1 = devread(cw->wdev, m, p2->iobuf);
34201a344a2SDavid du Colombier 		if(s1)
34301a344a2SDavid du Colombier 			goto stop1;
34401a344a2SDavid du Colombier 		if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) {
34501a344a2SDavid du Colombier 			print("reread C%lld W%lld didnt compare\n",
34601a344a2SDavid du Colombier 				(Wideoff)a, (Wideoff)m);
34701a344a2SDavid du Colombier 			goto stop1;
34801a344a2SDavid du Colombier 		}
34901a344a2SDavid du Colombier 		putbuf(p2);
35001a344a2SDavid du Colombier 	}
35101a344a2SDavid du Colombier 
35201a344a2SDavid du Colombier 	putbuf(p1);
35301a344a2SDavid du Colombier 	c->state = Cread;
35401a344a2SDavid du Colombier 	p->flags |= Bmod;
35501a344a2SDavid du Colombier 	putbuf(p);
35601a344a2SDavid du Colombier 
35701a344a2SDavid du Colombier 	if(m > wmax) {
35801a344a2SDavid du Colombier 		cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres);
35901a344a2SDavid du Colombier 		h = (Cache*)cb->iobuf;
36001a344a2SDavid du Colombier 		if(m > h->wmax)
36101a344a2SDavid du Colombier 			h->wmax = m;
36201a344a2SDavid du Colombier 		putbuf(cb);
36301a344a2SDavid du Colombier 	}
36401a344a2SDavid du Colombier 	cw->ncopy++;
36501a344a2SDavid du Colombier 	return 1;
36601a344a2SDavid du Colombier 
36701a344a2SDavid du Colombier stop1:
36801a344a2SDavid du Colombier 	putbuf(p2);
36901a344a2SDavid du Colombier 	putbuf(p1);
37001a344a2SDavid du Colombier 	c->state = Cdump1;
37101a344a2SDavid du Colombier 	p->flags |= Bmod;
37201a344a2SDavid du Colombier 	putbuf(p);
37301a344a2SDavid du Colombier 	return 1;
37401a344a2SDavid du Colombier 
37501a344a2SDavid du Colombier stop:
37601a344a2SDavid du Colombier 	putbuf(p1);
37701a344a2SDavid du Colombier 	putbuf(p);
37801a344a2SDavid du Colombier 	print("stopping dump!!\n");
37901a344a2SDavid du Colombier 	cw->nodump = 1;
38001a344a2SDavid du Colombier 	return 0;
38101a344a2SDavid du Colombier }
38201a344a2SDavid du Colombier 
38301a344a2SDavid du Colombier void
cwinit1(Device * dev)38401a344a2SDavid du Colombier cwinit1(Device *dev)
38501a344a2SDavid du Colombier {
38601a344a2SDavid du Colombier 	Cw *cw;
38701a344a2SDavid du Colombier 	static int first;
38801a344a2SDavid du Colombier 
38901a344a2SDavid du Colombier 	cw = dev->private;
39001a344a2SDavid du Colombier 	if(cw)
39101a344a2SDavid du Colombier 		return;
39201a344a2SDavid du Colombier 
39301a344a2SDavid du Colombier 	if(first == 0) {
39401a344a2SDavid du Colombier 		cmd_install("dump", "-- make dump backup to worm", cmd_dump);
39501a344a2SDavid du Colombier 		cmd_install("statw", "-- cache/worm stats", cmd_statw);
39601a344a2SDavid du Colombier 		cmd_install("cwcmd", "subcommand -- cache/worm errata", cmd_cwcmd);
39701a344a2SDavid du Colombier 		roflag = flag_install("ro", "-- ro reads and writes");
39801a344a2SDavid du Colombier 		first = 1;
39901a344a2SDavid du Colombier 	}
40001a344a2SDavid du Colombier 	cw = malloc(sizeof(Cw));
40101a344a2SDavid du Colombier 	dev->private = cw;
40201a344a2SDavid du Colombier 
40301a344a2SDavid du Colombier 	cw->allflag = 0;
40401a344a2SDavid du Colombier 
40501a344a2SDavid du Colombier 	cw->dev = dev;
40601a344a2SDavid du Colombier 	cw->cdev = CDEV(dev);
40701a344a2SDavid du Colombier 	cw->wdev = WDEV(dev);
40801a344a2SDavid du Colombier 	cw->rodev = RDEV(dev);
40901a344a2SDavid du Colombier 
41001a344a2SDavid du Colombier 	devinit(cw->cdev);
41101a344a2SDavid du Colombier 	devinit(cw->wdev);
41201a344a2SDavid du Colombier }
41301a344a2SDavid du Colombier 
41401a344a2SDavid du Colombier void
cwinit(Device * dev)41501a344a2SDavid du Colombier cwinit(Device *dev)
41601a344a2SDavid du Colombier {
41701a344a2SDavid du Colombier 	Cw *cw;
41801a344a2SDavid du Colombier 	Cache *h;
41901a344a2SDavid du Colombier 	Iobuf *cb, *p;
42001a344a2SDavid du Colombier 	Off l, m;
42101a344a2SDavid du Colombier 
42201a344a2SDavid du Colombier 	cwinit1(dev);
42301a344a2SDavid du Colombier 
42401a344a2SDavid du Colombier 	cw = dev->private;
42501a344a2SDavid du Colombier 	l = devsize(cw->wdev);
42601a344a2SDavid du Colombier 	cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres);
42701a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
42801a344a2SDavid du Colombier 	h->toytime = toytime() + SECOND(30);
42901a344a2SDavid du Colombier 	h->time = time(nil);
43001a344a2SDavid du Colombier 	m = h->wsize;
43101a344a2SDavid du Colombier 	if(l != m) {
43201a344a2SDavid du Colombier 		print("wdev changed size %lld to %lld\n",
43301a344a2SDavid du Colombier 			(Wideoff)m, (Wideoff)l);
43401a344a2SDavid du Colombier 		h->wsize = l;
43501a344a2SDavid du Colombier 		cb->flags |= Bmod;
43601a344a2SDavid du Colombier 	}
43701a344a2SDavid du Colombier 
43801a344a2SDavid du Colombier 	for(m=0; m<h->msize; m++) {
43901a344a2SDavid du Colombier 		p = getbuf(cw->cdev, h->maddr + m/BKPERBLK, Brd);
44001a344a2SDavid du Colombier 		if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK))
44101a344a2SDavid du Colombier 			panic("cwinit: checktag c bucket");
44201a344a2SDavid du Colombier 		putbuf(p);
44301a344a2SDavid du Colombier 	}
44401a344a2SDavid du Colombier 	putbuf(cb);
44501a344a2SDavid du Colombier }
44601a344a2SDavid du Colombier 
44701a344a2SDavid du Colombier Off
cwsaddr(Device * dev)44801a344a2SDavid du Colombier cwsaddr(Device *dev)
44901a344a2SDavid du Colombier {
45001a344a2SDavid du Colombier 	Iobuf *cb;
45101a344a2SDavid du Colombier 	Off sa;
45201a344a2SDavid du Colombier 
45301a344a2SDavid du Colombier 	cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
45401a344a2SDavid du Colombier 	sa = ((Cache*)cb->iobuf)->sbaddr;
45501a344a2SDavid du Colombier 	putbuf(cb);
45601a344a2SDavid du Colombier 	return sa;
45701a344a2SDavid du Colombier }
45801a344a2SDavid du Colombier 
45901a344a2SDavid du Colombier Off
cwraddr(Device * dev)46001a344a2SDavid du Colombier cwraddr(Device *dev)
46101a344a2SDavid du Colombier {
46201a344a2SDavid du Colombier 	Iobuf *cb;
46301a344a2SDavid du Colombier 	Off ra;
46401a344a2SDavid du Colombier 
46501a344a2SDavid du Colombier 	switch(dev->type) {
46601a344a2SDavid du Colombier 	default:
46701a344a2SDavid du Colombier 		print("unknown dev in cwraddr %Z\n", dev);
46801a344a2SDavid du Colombier 		return 1;
46901a344a2SDavid du Colombier 
47001a344a2SDavid du Colombier 	case Devcw:
47101a344a2SDavid du Colombier 		cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
47201a344a2SDavid du Colombier 		ra = ((Cache*)cb->iobuf)->cwraddr;
47301a344a2SDavid du Colombier 		break;
47401a344a2SDavid du Colombier 
47501a344a2SDavid du Colombier 	case Devro:
47601a344a2SDavid du Colombier 		cb = getbuf(CDEV(dev->ro.parent), CACHE_ADDR, Brd|Bres);
47701a344a2SDavid du Colombier 		ra = ((Cache*)cb->iobuf)->roraddr;
47801a344a2SDavid du Colombier 		break;
47901a344a2SDavid du Colombier 	}
48001a344a2SDavid du Colombier 	putbuf(cb);
48101a344a2SDavid du Colombier 	return ra;
48201a344a2SDavid du Colombier }
48301a344a2SDavid du Colombier 
48401a344a2SDavid du Colombier Devsize
cwsize(Device * dev)48501a344a2SDavid du Colombier cwsize(Device *dev)
48601a344a2SDavid du Colombier {
48701a344a2SDavid du Colombier 	Iobuf *cb;
48801a344a2SDavid du Colombier 	Devsize fs;
48901a344a2SDavid du Colombier 
49001a344a2SDavid du Colombier 	cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
49101a344a2SDavid du Colombier 	fs = ((Cache*)cb->iobuf)->fsize;
49201a344a2SDavid du Colombier 	putbuf(cb);
49301a344a2SDavid du Colombier 	return fs;
49401a344a2SDavid du Colombier }
49501a344a2SDavid du Colombier 
49601a344a2SDavid du Colombier int
cwread(Device * dev,Off b,void * c)49701a344a2SDavid du Colombier cwread(Device *dev, Off b, void *c)
49801a344a2SDavid du Colombier {
49901a344a2SDavid du Colombier 	return cwio(dev, b, c, Oread) == Cerror;
50001a344a2SDavid du Colombier }
50101a344a2SDavid du Colombier 
50201a344a2SDavid du Colombier int
cwwrite(Device * dev,Off b,void * c)50301a344a2SDavid du Colombier cwwrite(Device *dev, Off b, void *c)
50401a344a2SDavid du Colombier {
50501a344a2SDavid du Colombier 	return cwio(dev, b, c, Owrite) == Cerror;
50601a344a2SDavid du Colombier }
50701a344a2SDavid du Colombier 
50801a344a2SDavid du Colombier int
roread(Device * dev,Off b,void * c)50901a344a2SDavid du Colombier roread(Device *dev, Off b, void *c)
51001a344a2SDavid du Colombier {
51101a344a2SDavid du Colombier 	Device *d;
51201a344a2SDavid du Colombier 	int s;
51301a344a2SDavid du Colombier 
51401a344a2SDavid du Colombier 	/*
51501a344a2SDavid du Colombier 	 * maybe better is to try buffer pool first
51601a344a2SDavid du Colombier 	 */
51701a344a2SDavid du Colombier 	d = dev->ro.parent;
51801a344a2SDavid du Colombier 	if(d == 0 || d->type != Devcw ||
51901a344a2SDavid du Colombier 	   d->private == 0 || RDEV(d) != dev) {
52001a344a2SDavid du Colombier 		print("bad rodev %Z\n", dev);
52101a344a2SDavid du Colombier 		return 1;
52201a344a2SDavid du Colombier 	}
52301a344a2SDavid du Colombier 	s = cwio(d, b, 0, Onone);
52401a344a2SDavid du Colombier 	if(s == Cdump || s == Cdump1 || s == Cread) {
52501a344a2SDavid du Colombier 		s = cwio(d, b, c, Oread);
52601a344a2SDavid du Colombier 		if(s == Cdump || s == Cdump1 || s == Cread) {
52701a344a2SDavid du Colombier 			if(cons.flags & roflag)
52801a344a2SDavid du Colombier 				print("roread: %Z %lld -> %Z(hit)\n",
52901a344a2SDavid du Colombier 					dev, (Wideoff)b, d);
53001a344a2SDavid du Colombier 			return 0;
53101a344a2SDavid du Colombier 		}
53201a344a2SDavid du Colombier 	}
53301a344a2SDavid du Colombier 	if(cons.flags & roflag)
53401a344a2SDavid du Colombier 		print("roread: %Z %lld -> %Z(miss)\n",
53501a344a2SDavid du Colombier 			dev, (Wideoff)b, WDEV(d));
53601a344a2SDavid du Colombier 	return devread(WDEV(d), b, c);
53701a344a2SDavid du Colombier }
53801a344a2SDavid du Colombier 
53901a344a2SDavid du Colombier int
cwio(Device * dev,Off addr,void * buf,int opcode)54001a344a2SDavid du Colombier cwio(Device *dev, Off addr, void *buf, int opcode)
54101a344a2SDavid du Colombier {
54201a344a2SDavid du Colombier 	Iobuf *p, *p1, *p2, *cb;
54301a344a2SDavid du Colombier 	Cache *h;
54401a344a2SDavid du Colombier 	Bucket *b;
54501a344a2SDavid du Colombier 	Centry *c;
54601a344a2SDavid du Colombier 	Off bn, a1, a2, max, newmax;
54701a344a2SDavid du Colombier 	int state;
54801a344a2SDavid du Colombier 	Cw *cw;
54901a344a2SDavid du Colombier 
55001a344a2SDavid du Colombier 	cw = dev->private;
55101a344a2SDavid du Colombier 
55201a344a2SDavid du Colombier 	cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
55301a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
55401a344a2SDavid du Colombier 	if(toytime() >= h->toytime) {
55501a344a2SDavid du Colombier 		cb->flags |= Bmod;
55601a344a2SDavid du Colombier 		h->toytime = toytime() + SECOND(30);
55701a344a2SDavid du Colombier 		h->time = time(nil);
55801a344a2SDavid du Colombier 	}
55901a344a2SDavid du Colombier 
56001a344a2SDavid du Colombier 	if(addr < 0) {
56101a344a2SDavid du Colombier 		putbuf(cb);
56201a344a2SDavid du Colombier 		return Cerror;
56301a344a2SDavid du Colombier 	}
56401a344a2SDavid du Colombier 
56501a344a2SDavid du Colombier 	bn = addr % h->msize;
56601a344a2SDavid du Colombier 	a1 = h->maddr + bn/BKPERBLK;
567698b102bSDavid du Colombier 	if (oldcachefmt)
56801a344a2SDavid du Colombier 		a2 = bn*CEPERBK + h->caddr;
569698b102bSDavid du Colombier 	else
570698b102bSDavid du Colombier 		a2 = bn + h->caddr;
57101a344a2SDavid du Colombier 	max = h->wmax;
57201a344a2SDavid du Colombier 
57301a344a2SDavid du Colombier 	putbuf(cb);
57401a344a2SDavid du Colombier 	newmax = 0;
57501a344a2SDavid du Colombier 
57601a344a2SDavid du Colombier 	p = getbuf(cw->cdev, a1, Brd|Bmod);
57701a344a2SDavid du Colombier 	if(!p || checktag(p, Tbuck, a1))
57801a344a2SDavid du Colombier 		panic("cwio: checktag c bucket");
57901a344a2SDavid du Colombier 	b = (Bucket*)p->iobuf + bn%BKPERBLK;
58001a344a2SDavid du Colombier 
58101a344a2SDavid du Colombier 	c = getcentry(b, addr);
58201a344a2SDavid du Colombier 	if(c == 0) {
58301a344a2SDavid du Colombier 		putbuf(p);
58401a344a2SDavid du Colombier 		print("%Z disk cache bucket %lld is full\n",
58501a344a2SDavid du Colombier 			cw->cdev, (Wideoff)a1);
58601a344a2SDavid du Colombier 		return Cerror;
58701a344a2SDavid du Colombier 	}
588*e6d20ddfSDavid du Colombier 	if (oldcachefmt)
58901a344a2SDavid du Colombier 		a2 += c - b->entry;
590*e6d20ddfSDavid du Colombier 	else
591*e6d20ddfSDavid du Colombier 		a2 += (c - b->entry) * h->msize;
59201a344a2SDavid du Colombier 
59301a344a2SDavid du Colombier 	state = c->state;
59401a344a2SDavid du Colombier 	switch(opcode) {
59501a344a2SDavid du Colombier 	default:
59601a344a2SDavid du Colombier 		goto bad;
59701a344a2SDavid du Colombier 
59801a344a2SDavid du Colombier 	case Onone:
59901a344a2SDavid du Colombier 		break;
60001a344a2SDavid du Colombier 
60101a344a2SDavid du Colombier 	case Oread:
60201a344a2SDavid du Colombier 		switch(state) {
60301a344a2SDavid du Colombier 		default:
60401a344a2SDavid du Colombier 			goto bad;
60501a344a2SDavid du Colombier 
60601a344a2SDavid du Colombier 		case Cread:
60701a344a2SDavid du Colombier 			if(!devread(cw->cdev, a2, buf))
60801a344a2SDavid du Colombier 				break;
60901a344a2SDavid du Colombier 			c->state = Cnone;
61001a344a2SDavid du Colombier 
61101a344a2SDavid du Colombier 		case Cnone:
61201a344a2SDavid du Colombier 			if(devread(cw->wdev, addr, buf)) {
61301a344a2SDavid du Colombier 				state = Cerror;
61401a344a2SDavid du Colombier 				break;
61501a344a2SDavid du Colombier 			}
61601a344a2SDavid du Colombier 			if(addr > max)
61701a344a2SDavid du Colombier 				newmax = addr;
61801a344a2SDavid du Colombier 			if(!devwrite(cw->cdev, a2, buf))
61901a344a2SDavid du Colombier 				c->state = Cread;
62001a344a2SDavid du Colombier 			break;
62101a344a2SDavid du Colombier 
62201a344a2SDavid du Colombier 		case Cdirty:
62301a344a2SDavid du Colombier 		case Cdump:
62401a344a2SDavid du Colombier 		case Cdump1:
62501a344a2SDavid du Colombier 		case Cwrite:
62601a344a2SDavid du Colombier 			if(devread(cw->cdev, a2, buf))
62701a344a2SDavid du Colombier 				state = Cerror;
62801a344a2SDavid du Colombier 			break;
62901a344a2SDavid du Colombier 		}
63001a344a2SDavid du Colombier 		break;
63101a344a2SDavid du Colombier 
63201a344a2SDavid du Colombier 	case Owrite:
63301a344a2SDavid du Colombier 		switch(state) {
63401a344a2SDavid du Colombier 		default:
63501a344a2SDavid du Colombier 			goto bad;
63601a344a2SDavid du Colombier 
63701a344a2SDavid du Colombier 		case Cdump:
63801a344a2SDavid du Colombier 		case Cdump1:
63901a344a2SDavid du Colombier 			/*
64001a344a2SDavid du Colombier 			 * this is hard part -- a dump block must be
64101a344a2SDavid du Colombier 			 * sent to the worm if it is rewritten.
64201a344a2SDavid du Colombier 			 * if this causes an error, there is no
64301a344a2SDavid du Colombier 			 * place to save the dump1 data. the block
64401a344a2SDavid du Colombier 			 * is just reclassified as 'dump1' (botch)
64501a344a2SDavid du Colombier 			 */
64601a344a2SDavid du Colombier 			p1 = getbuf(devnone, Cwio1, 0);
64701a344a2SDavid du Colombier 			if(devread(cw->cdev, a2, p1->iobuf)) {
64801a344a2SDavid du Colombier 				putbuf(p1);
64901a344a2SDavid du Colombier 				print("cwio: write induced dump error - r cache\n");
65001a344a2SDavid du Colombier 
65101a344a2SDavid du Colombier 			casenone:
65201a344a2SDavid du Colombier 				if(devwrite(cw->cdev, a2, buf)) {
65301a344a2SDavid du Colombier 					state = Cerror;
65401a344a2SDavid du Colombier 					break;
65501a344a2SDavid du Colombier 				}
65601a344a2SDavid du Colombier 				c->state = Cdump1;
65701a344a2SDavid du Colombier 				break;
65801a344a2SDavid du Colombier 			}
65901a344a2SDavid du Colombier 			if(devwrite(cw->wdev, addr, p1->iobuf)) {
66001a344a2SDavid du Colombier 				p2 = getbuf(devnone, Cwio2, 0);
66101a344a2SDavid du Colombier 				if(devread(cw->wdev, addr, p2->iobuf)) {
66201a344a2SDavid du Colombier 					putbuf(p1);
66301a344a2SDavid du Colombier 					putbuf(p2);
66401a344a2SDavid du Colombier 					print("cwio: write induced dump error - r+w worm\n");
66501a344a2SDavid du Colombier 					goto casenone;
66601a344a2SDavid du Colombier 				}
66701a344a2SDavid du Colombier 				if(memcmp(p1->iobuf, p2->iobuf, RBUFSIZE)) {
66801a344a2SDavid du Colombier 					putbuf(p1);
66901a344a2SDavid du Colombier 					putbuf(p2);
67001a344a2SDavid du Colombier 					print("cwio: write induced dump error - w worm\n");
67101a344a2SDavid du Colombier 					goto casenone;
67201a344a2SDavid du Colombier 				}
67301a344a2SDavid du Colombier 				putbuf(p2);
67401a344a2SDavid du Colombier 			}
67501a344a2SDavid du Colombier 			putbuf(p1);
67601a344a2SDavid du Colombier 			c->state = Cread;
67701a344a2SDavid du Colombier 			if(addr > max)
67801a344a2SDavid du Colombier 				newmax = addr;
67901a344a2SDavid du Colombier 			cw->ncopy++;
68001a344a2SDavid du Colombier 
68101a344a2SDavid du Colombier 		case Cnone:
68201a344a2SDavid du Colombier 		case Cread:
68301a344a2SDavid du Colombier 			if(devwrite(cw->cdev, a2, buf)) {
68401a344a2SDavid du Colombier 				state = Cerror;
68501a344a2SDavid du Colombier 				break;
68601a344a2SDavid du Colombier 			}
68701a344a2SDavid du Colombier 			c->state = Cwrite;
68801a344a2SDavid du Colombier 			break;
68901a344a2SDavid du Colombier 
69001a344a2SDavid du Colombier 		case Cdirty:
69101a344a2SDavid du Colombier 		case Cwrite:
69201a344a2SDavid du Colombier 			if(devwrite(cw->cdev, a2, buf))
69301a344a2SDavid du Colombier 				state = Cerror;
69401a344a2SDavid du Colombier 			break;
69501a344a2SDavid du Colombier 		}
69601a344a2SDavid du Colombier 		break;
69701a344a2SDavid du Colombier 
69801a344a2SDavid du Colombier 	case Ogrow:
69901a344a2SDavid du Colombier 		if(state != Cnone) {
70001a344a2SDavid du Colombier 			print("%Z for block %lld cwgrow with state = %s\n",
70101a344a2SDavid du Colombier 				cw->cdev, (Wideoff)addr, cwnames[state]);
70201a344a2SDavid du Colombier 			break;
70301a344a2SDavid du Colombier 		}
70401a344a2SDavid du Colombier 		c->state = Cdirty;
70501a344a2SDavid du Colombier 		break;
70601a344a2SDavid du Colombier 
70701a344a2SDavid du Colombier 	case Odump:
70801a344a2SDavid du Colombier 		if(state != Cdirty) {	/* BOTCH */
70901a344a2SDavid du Colombier 			print("%Z for block %lld cwdump with state = %s\n",
71001a344a2SDavid du Colombier 				cw->cdev, (Wideoff)addr, cwnames[state]);
71101a344a2SDavid du Colombier 			break;
71201a344a2SDavid du Colombier 		}
71301a344a2SDavid du Colombier 		c->state = Cdump;
71401a344a2SDavid du Colombier 		cw->ndump++;	/* only called from dump command */
71501a344a2SDavid du Colombier 		break;
71601a344a2SDavid du Colombier 
71701a344a2SDavid du Colombier 	case Orele:
71801a344a2SDavid du Colombier 		if(state != Cwrite) {
71901a344a2SDavid du Colombier 			if(state != Cdump1)
72001a344a2SDavid du Colombier 				print("%Z for block %lld cwrele with state = %s\n",
72101a344a2SDavid du Colombier 					cw->cdev, (Wideoff)addr, cwnames[state]);
72201a344a2SDavid du Colombier 			break;
72301a344a2SDavid du Colombier 		}
72401a344a2SDavid du Colombier 		c->state = Cnone;
72501a344a2SDavid du Colombier 		break;
72601a344a2SDavid du Colombier 
72701a344a2SDavid du Colombier 	case Ofree:
72801a344a2SDavid du Colombier 		if(state == Cwrite || state == Cread)
72901a344a2SDavid du Colombier 			c->state = Cnone;
73001a344a2SDavid du Colombier 		break;
73101a344a2SDavid du Colombier 	}
73201a344a2SDavid du Colombier 	if(DEBUG)
73301a344a2SDavid du Colombier 		print("cwio: %Z %lld s=%s o=%s ns=%s\n",
73401a344a2SDavid du Colombier 			dev, (Wideoff)addr, cwnames[state],
73501a344a2SDavid du Colombier 			cwnames[opcode],
73601a344a2SDavid du Colombier 			cwnames[c->state]);
73701a344a2SDavid du Colombier 	putbuf(p);
73801a344a2SDavid du Colombier 	if(newmax) {
73901a344a2SDavid du Colombier 		cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bres);
74001a344a2SDavid du Colombier 		h = (Cache*)cb->iobuf;
74101a344a2SDavid du Colombier 		if(newmax > h->wmax)
74201a344a2SDavid du Colombier 			h->wmax = newmax;
74301a344a2SDavid du Colombier 		putbuf(cb);
74401a344a2SDavid du Colombier 	}
74501a344a2SDavid du Colombier 	return state;
74601a344a2SDavid du Colombier 
74701a344a2SDavid du Colombier bad:
74801a344a2SDavid du Colombier 	print("%Z block %lld cw state = %s; cw opcode = %s",
74901a344a2SDavid du Colombier 		dev, (Wideoff)addr, cwnames[state], cwnames[opcode]);
75001a344a2SDavid du Colombier 	return Cerror;
75101a344a2SDavid du Colombier }
75201a344a2SDavid du Colombier 
75301a344a2SDavid du Colombier 
75401a344a2SDavid du Colombier int
cwgrow(Device * dev,Superb * sb,int uid)75501a344a2SDavid du Colombier cwgrow(Device *dev, Superb *sb, int uid)
75601a344a2SDavid du Colombier {
75701a344a2SDavid du Colombier 	char str[NAMELEN];
75801a344a2SDavid du Colombier 	Iobuf *cb;
75901a344a2SDavid du Colombier 	Cache *h;
76001a344a2SDavid du Colombier 	Filsys *filsys;
76101a344a2SDavid du Colombier 	Off fs, nfs, ws;
76201a344a2SDavid du Colombier 
76301a344a2SDavid du Colombier 	cb = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bmod|Bres);
76401a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
76501a344a2SDavid du Colombier 	ws = h->wsize;
76601a344a2SDavid du Colombier 	fs = h->fsize;
76701a344a2SDavid du Colombier 	if(fs >= ws)
76801a344a2SDavid du Colombier 		return 0;
76901a344a2SDavid du Colombier 	nfs = fs + ADDFREE;
77001a344a2SDavid du Colombier 	if(nfs >= ws)
77101a344a2SDavid du Colombier 		nfs = ws;
77201a344a2SDavid du Colombier 	h->fsize = nfs;
77301a344a2SDavid du Colombier 	putbuf(cb);
77401a344a2SDavid du Colombier 
77501a344a2SDavid du Colombier 	sb->fsize = nfs;
77601a344a2SDavid du Colombier 	filsys = dev2fs(dev);
77701a344a2SDavid du Colombier 	if (filsys == nil)
77801a344a2SDavid du Colombier 		print("%Z", dev);
77901a344a2SDavid du Colombier 	else
78001a344a2SDavid du Colombier 		print("%s", filsys->name);
78101a344a2SDavid du Colombier 	uidtostr(str, uid, 1);
78201a344a2SDavid du Colombier 	print(" grow from %lld to %lld limit %lld by %s uid=%d\n",
78301a344a2SDavid du Colombier 		(Wideoff)fs, (Wideoff)nfs, (Wideoff)ws, str, uid);
78401a344a2SDavid du Colombier 	for(nfs--; nfs>=fs; nfs--)
78501a344a2SDavid du Colombier 		switch(cwio(dev, nfs, 0, Ogrow)) {
78601a344a2SDavid du Colombier 		case Cerror:
78701a344a2SDavid du Colombier 			return 0;
78801a344a2SDavid du Colombier 		case Cnone:
78901a344a2SDavid du Colombier 			addfree(dev, nfs, sb);
79001a344a2SDavid du Colombier 		}
79101a344a2SDavid du Colombier 	return 1;
79201a344a2SDavid du Colombier }
79301a344a2SDavid du Colombier 
79401a344a2SDavid du Colombier int
cwfree(Device * dev,Off addr)79501a344a2SDavid du Colombier cwfree(Device *dev, Off addr)
79601a344a2SDavid du Colombier {
79701a344a2SDavid du Colombier 	int state;
79801a344a2SDavid du Colombier 
79901a344a2SDavid du Colombier 	if(dev->type == Devcw) {
80001a344a2SDavid du Colombier 		state = cwio(dev, addr, 0, Ofree);
80101a344a2SDavid du Colombier 		if(state != Cdirty)
80201a344a2SDavid du Colombier 			return 1;	/* do not put in freelist */
80301a344a2SDavid du Colombier 	}
80401a344a2SDavid du Colombier 	return 0;			/* put in freelist */
80501a344a2SDavid du Colombier }
80601a344a2SDavid du Colombier 
80701a344a2SDavid du Colombier #ifdef unused
80801a344a2SDavid du Colombier int
bktcheck(Bucket * b)80901a344a2SDavid du Colombier bktcheck(Bucket *b)
81001a344a2SDavid du Colombier {
81101a344a2SDavid du Colombier 	Centry *c, *c1, *c2, *ce;
81201a344a2SDavid du Colombier 	int err;
81301a344a2SDavid du Colombier 
81401a344a2SDavid du Colombier 	err = 0;
81501a344a2SDavid du Colombier 	if(b->agegen < CEPERBK || b->agegen > MAXAGE) {
81601a344a2SDavid du Colombier 		print("agegen %ld\n", b->agegen);
81701a344a2SDavid du Colombier 		err = 1;
81801a344a2SDavid du Colombier 	}
81901a344a2SDavid du Colombier 
82001a344a2SDavid du Colombier 	ce = b->entry + CEPERBK;
82101a344a2SDavid du Colombier 	c1 = 0;		/* lowest age last pass */
82201a344a2SDavid du Colombier 	for(;;) {
82301a344a2SDavid du Colombier 		c2 = 0;		/* lowest age this pass */
82401a344a2SDavid du Colombier 		for(c = b->entry; c < ce; c++) {
82501a344a2SDavid du Colombier 			if(c1 != 0 && c != c1) {
82601a344a2SDavid du Colombier 				if(c->age == c1->age) {
82701a344a2SDavid du Colombier 					print("same age %d\n", c->age);
82801a344a2SDavid du Colombier 					err = 1;
82901a344a2SDavid du Colombier 				}
83001a344a2SDavid du Colombier 				if(c1->waddr == c->waddr)
83101a344a2SDavid du Colombier 				if(c1->state != Cnone)
83201a344a2SDavid du Colombier 				if(c->state != Cnone) {
83301a344a2SDavid du Colombier 					print("same waddr %lld\n",
83401a344a2SDavid du Colombier 						(Wideoff)c->waddr);
83501a344a2SDavid du Colombier 					err = 1;
83601a344a2SDavid du Colombier 				}
83701a344a2SDavid du Colombier 			}
83801a344a2SDavid du Colombier 			if(c1 != 0 && c->age <= c1->age)
83901a344a2SDavid du Colombier 				continue;
84001a344a2SDavid du Colombier 			if(c2 == 0 || c->age < c2->age)
84101a344a2SDavid du Colombier 				c2 = c;
84201a344a2SDavid du Colombier 		}
84301a344a2SDavid du Colombier 		if(c2 == 0)
84401a344a2SDavid du Colombier 			break;
84501a344a2SDavid du Colombier 		c1 = c2;
84601a344a2SDavid du Colombier 		if(c1->age >= b->agegen) {
84701a344a2SDavid du Colombier 			print("age >= generator %d %ld\n", c1->age, b->agegen);
84801a344a2SDavid du Colombier 			err = 1;
84901a344a2SDavid du Colombier 		}
85001a344a2SDavid du Colombier 	}
85101a344a2SDavid du Colombier 	return err;
85201a344a2SDavid du Colombier }
85301a344a2SDavid du Colombier #endif
85401a344a2SDavid du Colombier 
85501a344a2SDavid du Colombier void
resequence(Bucket * b)85601a344a2SDavid du Colombier resequence(Bucket *b)
85701a344a2SDavid du Colombier {
85801a344a2SDavid du Colombier 	Centry *c, *ce, *cr;
85901a344a2SDavid du Colombier 	int age, i;
86001a344a2SDavid du Colombier 
86101a344a2SDavid du Colombier 	ce = b->entry + CEPERBK;
86201a344a2SDavid du Colombier 	for(c = b->entry; c < ce; c++) {
86301a344a2SDavid du Colombier 		c->age += CEPERBK;
86401a344a2SDavid du Colombier 		if(c->age < CEPERBK)
86501a344a2SDavid du Colombier 			c->age = MAXAGE;
86601a344a2SDavid du Colombier 	}
86701a344a2SDavid du Colombier 	b->agegen += CEPERBK;
86801a344a2SDavid du Colombier 
86901a344a2SDavid du Colombier 	age = 0;
87001a344a2SDavid du Colombier 	for(i=0;; i++) {
87101a344a2SDavid du Colombier 		cr = 0;
87201a344a2SDavid du Colombier 		for(c = b->entry; c < ce; c++) {
87301a344a2SDavid du Colombier 			if(c->age < i)
87401a344a2SDavid du Colombier 				continue;
87501a344a2SDavid du Colombier 			if(cr == 0 || c->age < age) {
87601a344a2SDavid du Colombier 				cr = c;
87701a344a2SDavid du Colombier 				age = c->age;
87801a344a2SDavid du Colombier 			}
87901a344a2SDavid du Colombier 		}
88001a344a2SDavid du Colombier 		if(cr == 0)
88101a344a2SDavid du Colombier 			break;
88201a344a2SDavid du Colombier 		cr->age = i;
88301a344a2SDavid du Colombier 	}
88401a344a2SDavid du Colombier 	b->agegen = i;
88501a344a2SDavid du Colombier 	cons.nreseq++;
88601a344a2SDavid du Colombier }
88701a344a2SDavid du Colombier 
88801a344a2SDavid du Colombier Centry*
getcentry(Bucket * b,Off addr)88901a344a2SDavid du Colombier getcentry(Bucket *b, Off addr)
89001a344a2SDavid du Colombier {
89101a344a2SDavid du Colombier 	Centry *c, *ce, *cr;
89201a344a2SDavid du Colombier 	int s, age;
89301a344a2SDavid du Colombier 
89401a344a2SDavid du Colombier 	/*
89501a344a2SDavid du Colombier 	 * search for cache hit
89601a344a2SDavid du Colombier 	 * find oldest block as byproduct
89701a344a2SDavid du Colombier 	 */
89801a344a2SDavid du Colombier 	ce = b->entry + CEPERBK;
89901a344a2SDavid du Colombier 	age = 0;
90001a344a2SDavid du Colombier 	cr = 0;
90101a344a2SDavid du Colombier 	for(c = b->entry; c < ce; c++) {
90201a344a2SDavid du Colombier 		s = c->state;
90301a344a2SDavid du Colombier 		if(s == Cnone) {
90401a344a2SDavid du Colombier 			cr = c;
90501a344a2SDavid du Colombier 			age = 0;
90601a344a2SDavid du Colombier 			continue;
90701a344a2SDavid du Colombier 		}
90801a344a2SDavid du Colombier 		if(c->waddr == addr)
90901a344a2SDavid du Colombier 			goto found;
91001a344a2SDavid du Colombier 		if(s == Cread)
91101a344a2SDavid du Colombier 			if(cr == 0 || c->age < age) {
91201a344a2SDavid du Colombier 				cr = c;
91301a344a2SDavid du Colombier 				age = c->age;
91401a344a2SDavid du Colombier 			}
91501a344a2SDavid du Colombier 	}
91601a344a2SDavid du Colombier 
91701a344a2SDavid du Colombier 	/*
91801a344a2SDavid du Colombier 	 * remap entry
91901a344a2SDavid du Colombier 	 */
92001a344a2SDavid du Colombier 	c = cr;
92101a344a2SDavid du Colombier 	if(c == 0)
92201a344a2SDavid du Colombier 		return 0;	/* bucket is full */
92301a344a2SDavid du Colombier 
92401a344a2SDavid du Colombier 	c->state = Cnone;
92501a344a2SDavid du Colombier 	c->waddr = addr;
92601a344a2SDavid du Colombier 
92701a344a2SDavid du Colombier found:
92801a344a2SDavid du Colombier 	/*
92901a344a2SDavid du Colombier 	 * update the age to get filo cache.
93001a344a2SDavid du Colombier 	 * small number in age means old
93101a344a2SDavid du Colombier 	 */
93201a344a2SDavid du Colombier 	if(!cons.noage || c->state == Cnone) {
93301a344a2SDavid du Colombier 		age = b->agegen;
93401a344a2SDavid du Colombier 		c->age = age;
93501a344a2SDavid du Colombier 		age++;
93601a344a2SDavid du Colombier 		b->agegen = age;
93701a344a2SDavid du Colombier 		if(age < 0 || age >= MAXAGE)
93801a344a2SDavid du Colombier 			resequence(b);
93901a344a2SDavid du Colombier 	}
94001a344a2SDavid du Colombier 	return c;
94101a344a2SDavid du Colombier }
94201a344a2SDavid du Colombier 
94301a344a2SDavid du Colombier /*
94401a344a2SDavid du Colombier  * ream the cache
94501a344a2SDavid du Colombier  * calculate new buckets
94601a344a2SDavid du Colombier  */
94701a344a2SDavid du Colombier Iobuf*
cacheinit(Device * dev)94801a344a2SDavid du Colombier cacheinit(Device *dev)
94901a344a2SDavid du Colombier {
95001a344a2SDavid du Colombier 	Iobuf *cb, *p;
95101a344a2SDavid du Colombier 	Cache *h;
95201a344a2SDavid du Colombier 	Device *cdev;
95301a344a2SDavid du Colombier 	Off m;
95401a344a2SDavid du Colombier 
95501a344a2SDavid du Colombier 	print("cache init %Z\n", dev);
95601a344a2SDavid du Colombier 	cdev = CDEV(dev);
95701a344a2SDavid du Colombier 	devinit(cdev);
95801a344a2SDavid du Colombier 
95901a344a2SDavid du Colombier 	cb = getbuf(cdev, CACHE_ADDR, Bmod|Bres);
96001a344a2SDavid du Colombier 	memset(cb->iobuf, 0, RBUFSIZE);
96101a344a2SDavid du Colombier 	settag(cb, Tcache, QPSUPER);
96201a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
96301a344a2SDavid du Colombier 
96401a344a2SDavid du Colombier 	/*
96501a344a2SDavid du Colombier 	 * calculate csize such that
96601a344a2SDavid du Colombier 	 * tsize = msize/BKPERBLK + csize and
96701a344a2SDavid du Colombier 	 * msize = csize/CEPERBK
96801a344a2SDavid du Colombier 	 */
96901a344a2SDavid du Colombier 	h->maddr = CACHE_ADDR + 1;
97001a344a2SDavid du Colombier 	m = devsize(cdev) - h->maddr;
97101a344a2SDavid du Colombier 	h->csize = ((Devsize)(m-1) * CEPERBK*BKPERBLK) / (CEPERBK*BKPERBLK+1);
97201a344a2SDavid du Colombier 	h->msize = h->csize/CEPERBK - 5;
97301a344a2SDavid du Colombier 	while(!prime(h->msize))
97401a344a2SDavid du Colombier 		h->msize--;
97501a344a2SDavid du Colombier 	h->csize = h->msize*CEPERBK;
97601a344a2SDavid du Colombier 	h->caddr = h->maddr + (h->msize+BKPERBLK-1)/BKPERBLK;
97701a344a2SDavid du Colombier 	h->wsize = devsize(WDEV(dev));
97801a344a2SDavid du Colombier 
97901a344a2SDavid du Colombier 	if(h->msize <= 0)
98001a344a2SDavid du Colombier 		panic("cache too small");
98101a344a2SDavid du Colombier 	if(h->caddr + h->csize > m)
98201a344a2SDavid du Colombier 		panic("cache size error");
98301a344a2SDavid du Colombier 
98401a344a2SDavid du Colombier 	/*
98501a344a2SDavid du Colombier 	 * setup cache map
98601a344a2SDavid du Colombier 	 */
98701a344a2SDavid du Colombier 	for(m=h->maddr; m<h->caddr; m++) {
98801a344a2SDavid du Colombier 		p = getbuf(cdev, m, Bmod);
98901a344a2SDavid du Colombier 		memset(p->iobuf, 0, RBUFSIZE);
99001a344a2SDavid du Colombier 		settag(p, Tbuck, m);
99101a344a2SDavid du Colombier 		putbuf(p);
99201a344a2SDavid du Colombier 	}
99301a344a2SDavid du Colombier 	print("done cacheinit\n");
99401a344a2SDavid du Colombier 	return cb;
99501a344a2SDavid du Colombier }
99601a344a2SDavid du Colombier 
99701a344a2SDavid du Colombier Off
getstartsb(Device * dev)99801a344a2SDavid du Colombier getstartsb(Device *dev)
99901a344a2SDavid du Colombier {
100001a344a2SDavid du Colombier 	Filsys *f;
100101a344a2SDavid du Colombier 	Startsb *s;
100201a344a2SDavid du Colombier 
100301a344a2SDavid du Colombier 	for(f=filsys; f->name; f++)
100401a344a2SDavid du Colombier 		if(devcmpr(f->dev, dev) == 0) {
100501a344a2SDavid du Colombier 			for(s=startsb; s->name; s++)
100601a344a2SDavid du Colombier 				if(strcmp(f->name, s->name) == 0)
100701a344a2SDavid du Colombier 					return s->startsb;
100801a344a2SDavid du Colombier 			print(
100901a344a2SDavid du Colombier 		"getstartsb: no special starting superblock for %Z %s\n",
101001a344a2SDavid du Colombier 				dev, f->name);
101101a344a2SDavid du Colombier 			return FIRST;
101201a344a2SDavid du Colombier 		}
101301a344a2SDavid du Colombier 	print("getstartsb: no filsys for device %Z\n", dev);
101401a344a2SDavid du Colombier 	return FIRST;
101501a344a2SDavid du Colombier }
101601a344a2SDavid du Colombier 
101701a344a2SDavid du Colombier /*
101801a344a2SDavid du Colombier  * ream the cache
101901a344a2SDavid du Colombier  * calculate new buckets
102001a344a2SDavid du Colombier  * get superblock from
102101a344a2SDavid du Colombier  * last worm dump block.
102201a344a2SDavid du Colombier  */
102301a344a2SDavid du Colombier void
cwrecover(Device * dev)102401a344a2SDavid du Colombier cwrecover(Device *dev)
102501a344a2SDavid du Colombier {
102601a344a2SDavid du Colombier 	Iobuf *p, *cb;
102701a344a2SDavid du Colombier 	Cache *h;
102801a344a2SDavid du Colombier 	Superb *s;
102901a344a2SDavid du Colombier 	Off m, baddr;
103001a344a2SDavid du Colombier 	Device *wdev;
103101a344a2SDavid du Colombier 
103201a344a2SDavid du Colombier //	print("cwrecover %Z\n", dev);	// DEBUG
103301a344a2SDavid du Colombier 	cwinit1(dev);
103401a344a2SDavid du Colombier 	wdev = WDEV(dev);
103501a344a2SDavid du Colombier 
103601a344a2SDavid du Colombier 	p = getbuf(devnone, Cwxx1, 0);
103701a344a2SDavid du Colombier 	s = (Superb*)p->iobuf;
103801a344a2SDavid du Colombier 	baddr = 0;
103901a344a2SDavid du Colombier 	m = getstartsb(dev);
104001a344a2SDavid du Colombier 	localconfinit();
104101a344a2SDavid du Colombier 	if(conf.firstsb)
104201a344a2SDavid du Colombier 		m = conf.firstsb;
104301a344a2SDavid du Colombier 	for(;;) {
104401a344a2SDavid du Colombier 		memset(p->iobuf, 0, RBUFSIZE);
104501a344a2SDavid du Colombier 		if(devread(wdev, m, p->iobuf) ||
104601a344a2SDavid du Colombier 		   checktag(p, Tsuper, QPSUPER))
104701a344a2SDavid du Colombier 			break;
104801a344a2SDavid du Colombier 		baddr = m;
104901a344a2SDavid du Colombier 		m = s->next;
105001a344a2SDavid du Colombier 		print("dump %lld is good; %lld next\n", (Wideoff)baddr, (Wideoff)m);
105101a344a2SDavid du Colombier 		if(baddr == conf.recovsb)
105201a344a2SDavid du Colombier 			break;
105301a344a2SDavid du Colombier 	}
105401a344a2SDavid du Colombier 	putbuf(p);
105501a344a2SDavid du Colombier 	if(!baddr)
105601a344a2SDavid du Colombier 		panic("recover: no superblock");
105701a344a2SDavid du Colombier 
105801a344a2SDavid du Colombier 	p = getbuf(wdev, baddr, Brd);
105901a344a2SDavid du Colombier 	s = (Superb*)p->iobuf;
106001a344a2SDavid du Colombier 
106101a344a2SDavid du Colombier 	cb = cacheinit(dev);
106201a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
106301a344a2SDavid du Colombier 	h->sbaddr = baddr;
106401a344a2SDavid du Colombier 	h->cwraddr = s->cwraddr;
106501a344a2SDavid du Colombier 	h->roraddr = s->roraddr;
106601a344a2SDavid du Colombier 	h->fsize = s->fsize + 100;		/* this must be conservative */
106701a344a2SDavid du Colombier 	if(conf.recovcw)
106801a344a2SDavid du Colombier 		h->cwraddr = conf.recovcw;
106901a344a2SDavid du Colombier 	if(conf.recovro)
107001a344a2SDavid du Colombier 		h->roraddr = conf.recovro;
107101a344a2SDavid du Colombier 
107201a344a2SDavid du Colombier 	putbuf(cb);
107301a344a2SDavid du Colombier 	putbuf(p);
107401a344a2SDavid du Colombier 
107501a344a2SDavid du Colombier 	p = getbuf(dev, baddr, Brd|Bmod);
107601a344a2SDavid du Colombier 	s = (Superb*)p->iobuf;
107701a344a2SDavid du Colombier 
107801a344a2SDavid du Colombier 	memset(&s->fbuf, 0, sizeof(s->fbuf));
107901a344a2SDavid du Colombier 	s->fbuf.free[0] = 0;
108001a344a2SDavid du Colombier 	s->fbuf.nfree = 1;
108101a344a2SDavid du Colombier 	s->tfree = 0;
108201a344a2SDavid du Colombier 	if(conf.recovcw)
108301a344a2SDavid du Colombier 		s->cwraddr = conf.recovcw;
108401a344a2SDavid du Colombier 	if(conf.recovro)
108501a344a2SDavid du Colombier 		s->roraddr = conf.recovro;
108601a344a2SDavid du Colombier 
108701a344a2SDavid du Colombier 	putbuf(p);
108801a344a2SDavid du Colombier 	print("done recover\n");
108901a344a2SDavid du Colombier }
109001a344a2SDavid du Colombier 
109101a344a2SDavid du Colombier /*
109201a344a2SDavid du Colombier  * ream the cache
109301a344a2SDavid du Colombier  * calculate new buckets
109401a344a2SDavid du Colombier  * initialize superblock.
109501a344a2SDavid du Colombier  */
109601a344a2SDavid du Colombier void
cwream(Device * dev)109701a344a2SDavid du Colombier cwream(Device *dev)
109801a344a2SDavid du Colombier {
109901a344a2SDavid du Colombier 	Iobuf *p, *cb;
110001a344a2SDavid du Colombier 	Cache *h;
110101a344a2SDavid du Colombier 	Superb *s;
110201a344a2SDavid du Colombier 	Off m, baddr;
110301a344a2SDavid du Colombier 	Device *cdev;
110401a344a2SDavid du Colombier 
110501a344a2SDavid du Colombier 	print("cwream %Z\n", dev);
110601a344a2SDavid du Colombier 	cwinit1(dev);
110701a344a2SDavid du Colombier 	cdev = CDEV(dev);
110801a344a2SDavid du Colombier 	devinit(cdev);
110901a344a2SDavid du Colombier 
111001a344a2SDavid du Colombier 	baddr = FIRST;	/*	baddr   = super addr
111101a344a2SDavid du Colombier 				baddr+1 = cw root
111201a344a2SDavid du Colombier 				baddr+2 = ro root
111301a344a2SDavid du Colombier 				baddr+3 = reserved next superblock */
111401a344a2SDavid du Colombier 
111501a344a2SDavid du Colombier 	cb = cacheinit(dev);
111601a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
111701a344a2SDavid du Colombier 
111801a344a2SDavid du Colombier 	h->sbaddr = baddr;
111901a344a2SDavid du Colombier 	h->cwraddr = baddr+1;
112001a344a2SDavid du Colombier 	h->roraddr = baddr+2;
112101a344a2SDavid du Colombier 	h->fsize = 0;	/* prevents superream from freeing */
112201a344a2SDavid du Colombier 
112301a344a2SDavid du Colombier 	putbuf(cb);
112401a344a2SDavid du Colombier 
112501a344a2SDavid du Colombier 	for(m=0; m<3; m++)
112601a344a2SDavid du Colombier 		cwio(dev, baddr+m, 0, Ogrow);
112701a344a2SDavid du Colombier 	superream(dev, baddr);
112801a344a2SDavid du Colombier 	rootream(dev, baddr+1);			/* cw root */
112901a344a2SDavid du Colombier 	rootream(dev, baddr+2);			/* ro root */
113001a344a2SDavid du Colombier 
113101a344a2SDavid du Colombier 	cb = getbuf(cdev, CACHE_ADDR, Brd|Bmod|Bres);
113201a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
113301a344a2SDavid du Colombier 	h->fsize = baddr+4;
113401a344a2SDavid du Colombier 	putbuf(cb);
113501a344a2SDavid du Colombier 
113601a344a2SDavid du Colombier 	p = getbuf(dev, baddr, Brd|Bmod|Bimm);
113701a344a2SDavid du Colombier 	s = (Superb*)p->iobuf;
113801a344a2SDavid du Colombier 	s->last = baddr;
113901a344a2SDavid du Colombier 	s->cwraddr = baddr+1;
114001a344a2SDavid du Colombier 	s->roraddr = baddr+2;
114101a344a2SDavid du Colombier 	s->next = baddr+3;
114201a344a2SDavid du Colombier 	s->fsize = baddr+4;
114301a344a2SDavid du Colombier 	putbuf(p);
114401a344a2SDavid du Colombier 
114501a344a2SDavid du Colombier 	for(m=0; m<3; m++)
114601a344a2SDavid du Colombier 		cwio(dev, baddr+m, 0, Odump);
114701a344a2SDavid du Colombier }
114801a344a2SDavid du Colombier 
114901a344a2SDavid du Colombier Off
rewalk1(Cw * cw,Off addr,int slot,Wpath * up)115001a344a2SDavid du Colombier rewalk1(Cw *cw, Off addr, int slot, Wpath *up)
115101a344a2SDavid du Colombier {
115201a344a2SDavid du Colombier 	Iobuf *p, *p1;
115301a344a2SDavid du Colombier 	Dentry *d;
115401a344a2SDavid du Colombier 
115501a344a2SDavid du Colombier 	if(up == 0)
115601a344a2SDavid du Colombier 		return cwraddr(cw->dev);
115701a344a2SDavid du Colombier 	up->addr = rewalk1(cw, up->addr, up->slot, up->up);
115801a344a2SDavid du Colombier 	p = getbuf(cw->dev, up->addr, Brd|Bmod);
115901a344a2SDavid du Colombier 	d = getdir(p, up->slot);
116001a344a2SDavid du Colombier 	if(!d || !(d->mode & DALLOC)) {
116101a344a2SDavid du Colombier 		print("rewalk1 1\n");
116201a344a2SDavid du Colombier 		if(p)
116301a344a2SDavid du Colombier 			putbuf(p);
116401a344a2SDavid du Colombier 		return addr;
116501a344a2SDavid du Colombier 	}
116601a344a2SDavid du Colombier 	p1 = dnodebuf(p, d, slot/DIRPERBUF, 0, 0);
116701a344a2SDavid du Colombier 	if(!p1) {
116801a344a2SDavid du Colombier 		print("rewalk1 2\n");
116901a344a2SDavid du Colombier 		if(p)
117001a344a2SDavid du Colombier 			putbuf(p);
117101a344a2SDavid du Colombier 		return addr;
117201a344a2SDavid du Colombier 	}
117301a344a2SDavid du Colombier 	if(DEBUG)
117401a344a2SDavid du Colombier 		print("rewalk1 %lld to %lld \"%s\"\n",
117501a344a2SDavid du Colombier 			(Wideoff)addr, (Wideoff)p1->addr, d->name);
117601a344a2SDavid du Colombier 	addr = p1->addr;
117701a344a2SDavid du Colombier 	p1->flags |= Bmod;
117801a344a2SDavid du Colombier 	putbuf(p1);
117901a344a2SDavid du Colombier 	putbuf(p);
118001a344a2SDavid du Colombier 	return addr;
118101a344a2SDavid du Colombier }
118201a344a2SDavid du Colombier 
118301a344a2SDavid du Colombier Off
rewalk2(Cw * cw,Off addr,int slot,Wpath * up)118401a344a2SDavid du Colombier rewalk2(Cw *cw, Off addr, int slot, Wpath *up)
118501a344a2SDavid du Colombier {
118601a344a2SDavid du Colombier 	Iobuf *p, *p1;
118701a344a2SDavid du Colombier 	Dentry *d;
118801a344a2SDavid du Colombier 
118901a344a2SDavid du Colombier 	if(up == 0)
119001a344a2SDavid du Colombier 		return cwraddr(cw->rodev);
119101a344a2SDavid du Colombier 	up->addr = rewalk2(cw, up->addr, up->slot, up->up);
119201a344a2SDavid du Colombier 	p = getbuf(cw->rodev, up->addr, Brd);
119301a344a2SDavid du Colombier 	d = getdir(p, up->slot);
119401a344a2SDavid du Colombier 	if(!d || !(d->mode & DALLOC)) {
119501a344a2SDavid du Colombier 		print("rewalk2 1\n");
119601a344a2SDavid du Colombier 		if(p)
119701a344a2SDavid du Colombier 			putbuf(p);
119801a344a2SDavid du Colombier 		return addr;
119901a344a2SDavid du Colombier 	}
120001a344a2SDavid du Colombier 	p1 = dnodebuf(p, d, slot/DIRPERBUF, 0, 0);
120101a344a2SDavid du Colombier 	if(!p1) {
120201a344a2SDavid du Colombier 		print("rewalk2 2\n");
120301a344a2SDavid du Colombier 		if(p)
120401a344a2SDavid du Colombier 			putbuf(p);
120501a344a2SDavid du Colombier 		return addr;
120601a344a2SDavid du Colombier 	}
120701a344a2SDavid du Colombier 	if(DEBUG)
120801a344a2SDavid du Colombier 		print("rewalk2 %lld to %lld \"%s\"\n",
120901a344a2SDavid du Colombier 			(Wideoff)addr, (Wideoff)p1->addr, d->name);
121001a344a2SDavid du Colombier 	addr = p1->addr;
121101a344a2SDavid du Colombier 	putbuf(p1);
121201a344a2SDavid du Colombier 	putbuf(p);
121301a344a2SDavid du Colombier 	return addr;
121401a344a2SDavid du Colombier }
121501a344a2SDavid du Colombier 
121601a344a2SDavid du Colombier void
rewalk(Cw * cw)121701a344a2SDavid du Colombier rewalk(Cw *cw)
121801a344a2SDavid du Colombier {
121901a344a2SDavid du Colombier 	int h;
122001a344a2SDavid du Colombier 	File *f;
122101a344a2SDavid du Colombier 
122201a344a2SDavid du Colombier 	for(h=0; h<nelem(flist); h++)
122301a344a2SDavid du Colombier 		for(f=flist[h]; f; f=f->next) {
122401a344a2SDavid du Colombier 			if(!f->fs)
122501a344a2SDavid du Colombier 				continue;
122601a344a2SDavid du Colombier 			if(cw->dev == f->fs->dev)
122701a344a2SDavid du Colombier 				f->addr = rewalk1(cw, f->addr, f->slot, f->wpath);
122801a344a2SDavid du Colombier 			else
122901a344a2SDavid du Colombier 			if(cw->rodev == f->fs->dev)
123001a344a2SDavid du Colombier 				f->addr = rewalk2(cw, f->addr, f->slot, f->wpath);
123101a344a2SDavid du Colombier 		}
123201a344a2SDavid du Colombier }
123301a344a2SDavid du Colombier 
123401a344a2SDavid du Colombier Off
split(Cw * cw,Iobuf * p,Off addr)123501a344a2SDavid du Colombier split(Cw *cw, Iobuf *p, Off addr)
123601a344a2SDavid du Colombier {
123701a344a2SDavid du Colombier 	Off na;
123801a344a2SDavid du Colombier 	int state;
123901a344a2SDavid du Colombier 
124001a344a2SDavid du Colombier 	na = 0;
124101a344a2SDavid du Colombier 	if(p && (p->flags & Bmod)) {
124201a344a2SDavid du Colombier 		p->flags |= Bimm;
124301a344a2SDavid du Colombier 		putbuf(p);
124401a344a2SDavid du Colombier 		p = 0;
124501a344a2SDavid du Colombier 	}
124601a344a2SDavid du Colombier 	state = cwio(cw->dev, addr, 0, Onone);	/* read the state (twice?) */
124701a344a2SDavid du Colombier 	switch(state) {
124801a344a2SDavid du Colombier 	default:
124901a344a2SDavid du Colombier 		panic("split: unknown state %s", cwnames[state]);
125001a344a2SDavid du Colombier 
125101a344a2SDavid du Colombier 	case Cerror:
125201a344a2SDavid du Colombier 	case Cnone:
125301a344a2SDavid du Colombier 	case Cdump:
125401a344a2SDavid du Colombier 	case Cread:
125501a344a2SDavid du Colombier 		break;
125601a344a2SDavid du Colombier 
125701a344a2SDavid du Colombier 	case Cdump1:
125801a344a2SDavid du Colombier 	case Cwrite:
125901a344a2SDavid du Colombier 		/*
126001a344a2SDavid du Colombier 		 * botch.. could be done by relabeling
126101a344a2SDavid du Colombier 		 */
126201a344a2SDavid du Colombier 		if(!p) {
126301a344a2SDavid du Colombier 			p = getbuf(cw->dev, addr, Brd);
126401a344a2SDavid du Colombier 			if(!p) {
126501a344a2SDavid du Colombier 				print("split: null getbuf\n");
126601a344a2SDavid du Colombier 				break;
126701a344a2SDavid du Colombier 			}
126801a344a2SDavid du Colombier 		}
126901a344a2SDavid du Colombier 		na = cw->fsize;
127001a344a2SDavid du Colombier 		cw->fsize = na+1;
127101a344a2SDavid du Colombier 		cwio(cw->dev, na, 0, Ogrow);
127201a344a2SDavid du Colombier 		cwio(cw->dev, na, p->iobuf, Owrite);
127301a344a2SDavid du Colombier 		cwio(cw->dev, na, 0, Odump);
127401a344a2SDavid du Colombier 		cwio(cw->dev, addr, 0, Orele);
127501a344a2SDavid du Colombier 		break;
127601a344a2SDavid du Colombier 
127701a344a2SDavid du Colombier 	case Cdirty:
127801a344a2SDavid du Colombier 		cwio(cw->dev, addr, 0, Odump);
127901a344a2SDavid du Colombier 		break;
128001a344a2SDavid du Colombier 	}
128101a344a2SDavid du Colombier 	if(p)
128201a344a2SDavid du Colombier 		putbuf(p);
128301a344a2SDavid du Colombier 	return na;
128401a344a2SDavid du Colombier }
128501a344a2SDavid du Colombier 
128601a344a2SDavid du Colombier int
isdirty(Cw * cw,Iobuf * p,Off addr,int tag)128701a344a2SDavid du Colombier isdirty(Cw *cw, Iobuf *p, Off addr, int tag)
128801a344a2SDavid du Colombier {
128901a344a2SDavid du Colombier 	int s;
129001a344a2SDavid du Colombier 
129101a344a2SDavid du Colombier 	if(p && (p->flags & Bmod))
129201a344a2SDavid du Colombier 		return 1;
129301a344a2SDavid du Colombier 	s = cwio(cw->dev, addr, 0, Onone);
129401a344a2SDavid du Colombier 	if(s == Cdirty || s == Cwrite)
129501a344a2SDavid du Colombier 		return 1;
129601a344a2SDavid du Colombier 	if(tag >= Tind1 && tag <= Tmaxind)
129701a344a2SDavid du Colombier 		/* botch, get these modified */
129801a344a2SDavid du Colombier 		if(s != Cnone)
129901a344a2SDavid du Colombier 			return 1;
130001a344a2SDavid du Colombier 	return 0;
130101a344a2SDavid du Colombier }
130201a344a2SDavid du Colombier 
130301a344a2SDavid du Colombier Off
cwrecur(Cw * cw,Off addr,int tag,int tag1,long qp)130401a344a2SDavid du Colombier cwrecur(Cw *cw, Off addr, int tag, int tag1, long qp)
130501a344a2SDavid du Colombier {
130601a344a2SDavid du Colombier 	Iobuf *p;
130701a344a2SDavid du Colombier 	Dentry *d;
130801a344a2SDavid du Colombier 	int i, j, shouldstop;
130901a344a2SDavid du Colombier 	Off na;
131001a344a2SDavid du Colombier 	char *np;
131101a344a2SDavid du Colombier 
131201a344a2SDavid du Colombier 	shouldstop = 0;
131301a344a2SDavid du Colombier 	p = getbuf(cw->dev, addr, Bprobe);
131401a344a2SDavid du Colombier 	if(!isdirty(cw, p, addr, tag)) {
131501a344a2SDavid du Colombier 		if(!cw->all) {
131601a344a2SDavid du Colombier 			if(DEBUG)
131701a344a2SDavid du Colombier 				print("cwrecur: %lld t=%s not dirty %s\n",
131801a344a2SDavid du Colombier 					(Wideoff)addr, tagnames[tag], cw->name);
131901a344a2SDavid du Colombier 			if(p)
132001a344a2SDavid du Colombier 				putbuf(p);
132101a344a2SDavid du Colombier 			return 0;
132201a344a2SDavid du Colombier 		}
132301a344a2SDavid du Colombier 		shouldstop = 1;
132401a344a2SDavid du Colombier 	}
132501a344a2SDavid du Colombier 	if(DEBUG)
132601a344a2SDavid du Colombier 		print("cwrecur: %lld t=%s %s\n",
132701a344a2SDavid du Colombier 			(Wideoff)addr, tagnames[tag], cw->name);
132801a344a2SDavid du Colombier 	if(cw->depth >= 100) {
132901a344a2SDavid du Colombier 		print("dump depth too great %s\n", cw->name);
133001a344a2SDavid du Colombier 		if(p)
133101a344a2SDavid du Colombier 			putbuf(p);
133201a344a2SDavid du Colombier 		return 0;
133301a344a2SDavid du Colombier 	}
133401a344a2SDavid du Colombier 	cw->depth++;
133501a344a2SDavid du Colombier 
133601a344a2SDavid du Colombier 	switch(tag) {
133701a344a2SDavid du Colombier 	default:
133801a344a2SDavid du Colombier 		print("cwrecur: unknown tag %d %s\n", tag, cw->name);
133901a344a2SDavid du Colombier 
134001a344a2SDavid du Colombier 	case Tfile:
134101a344a2SDavid du Colombier 		break;
134201a344a2SDavid du Colombier 
134301a344a2SDavid du Colombier 	case Tsuper:
134401a344a2SDavid du Colombier 	case Tdir:
134501a344a2SDavid du Colombier 		if(!p) {
134601a344a2SDavid du Colombier 			p = getbuf(cw->dev, addr, Brd);
134701a344a2SDavid du Colombier 			if(!p) {
134801a344a2SDavid du Colombier 				print("cwrecur: Tdir p null %s\n",
134901a344a2SDavid du Colombier 					cw->name);
135001a344a2SDavid du Colombier 				break;
135101a344a2SDavid du Colombier 			}
135201a344a2SDavid du Colombier 		}
135301a344a2SDavid du Colombier 		if(tag == Tdir) {
135401a344a2SDavid du Colombier 			cw->namepad[0] = 0;	/* force room */
135501a344a2SDavid du Colombier 			np = strchr(cw->name, 0);
135601a344a2SDavid du Colombier 			*np++ = '/';
135701a344a2SDavid du Colombier 		} else {
135801a344a2SDavid du Colombier 			np = 0;	/* set */
135901a344a2SDavid du Colombier 			cw->name[0] = 0;
136001a344a2SDavid du Colombier 		}
136101a344a2SDavid du Colombier 
136201a344a2SDavid du Colombier 		for(i=0; i<DIRPERBUF; i++) {
136301a344a2SDavid du Colombier 			d = getdir(p, i);
136401a344a2SDavid du Colombier 			if(!(d->mode & DALLOC))
136501a344a2SDavid du Colombier 				continue;
136601a344a2SDavid du Colombier 			qp = d->qid.path & ~QPDIR;
136701a344a2SDavid du Colombier 			if(tag == Tdir)
136801a344a2SDavid du Colombier 				strncpy(np, d->name, NAMELEN);
136901a344a2SDavid du Colombier 			else
137001a344a2SDavid du Colombier 			if(i > 0)
137101a344a2SDavid du Colombier 				print("cwrecur: root with >1 directory\n");
137201a344a2SDavid du Colombier 			tag1 = Tfile;
137301a344a2SDavid du Colombier 			if(d->mode & DDIR)
137401a344a2SDavid du Colombier 				tag1 = Tdir;
137501a344a2SDavid du Colombier 			for(j=0; j<NDBLOCK; j++) {
137601a344a2SDavid du Colombier 				na = d->dblock[j];
137701a344a2SDavid du Colombier 				if(na) {
137801a344a2SDavid du Colombier 					na = cwrecur(cw, na, tag1, 0, qp);
137901a344a2SDavid du Colombier 					if(na) {
138001a344a2SDavid du Colombier 						d->dblock[j] = na;
138101a344a2SDavid du Colombier 						p->flags |= Bmod;
138201a344a2SDavid du Colombier 					}
138301a344a2SDavid du Colombier 				}
138401a344a2SDavid du Colombier 			}
138501a344a2SDavid du Colombier 			for (j = 0; j < NIBLOCK; j++) {
138601a344a2SDavid du Colombier 				na = d->iblocks[j];
138701a344a2SDavid du Colombier 				if(na) {
138801a344a2SDavid du Colombier 					na = cwrecur(cw, na, Tind1+j, tag1, qp);
138901a344a2SDavid du Colombier 					if(na) {
139001a344a2SDavid du Colombier 						d->iblocks[j] = na;
139101a344a2SDavid du Colombier 						p->flags |= Bmod;
139201a344a2SDavid du Colombier 					}
139301a344a2SDavid du Colombier 				}
139401a344a2SDavid du Colombier 			}
139501a344a2SDavid du Colombier 		}
139601a344a2SDavid du Colombier 		break;
139701a344a2SDavid du Colombier 
139801a344a2SDavid du Colombier 	case Tind1:
139901a344a2SDavid du Colombier 		j = tag1;
140001a344a2SDavid du Colombier 		tag1 = 0;
140101a344a2SDavid du Colombier 		goto tind;
140201a344a2SDavid du Colombier 
140301a344a2SDavid du Colombier 	case Tind2:
140401a344a2SDavid du Colombier #ifndef COMPAT32
140501a344a2SDavid du Colombier 	case Tind3:
140601a344a2SDavid du Colombier 	case Tind4:
140701a344a2SDavid du Colombier 	/* add more Tind tags here ... */
140801a344a2SDavid du Colombier #endif
140901a344a2SDavid du Colombier 		j = tag-1;
141001a344a2SDavid du Colombier 	tind:
141101a344a2SDavid du Colombier 		if(!p) {
141201a344a2SDavid du Colombier 			p = getbuf(cw->dev, addr, Brd);
141301a344a2SDavid du Colombier 			if(!p) {
141401a344a2SDavid du Colombier 				print("cwrecur: Tind p null %s\n", cw->name);
141501a344a2SDavid du Colombier 				break;
141601a344a2SDavid du Colombier 			}
141701a344a2SDavid du Colombier 		}
141801a344a2SDavid du Colombier 		for(i=0; i<INDPERBUF; i++) {
141901a344a2SDavid du Colombier 			na = ((Off *)p->iobuf)[i];
142001a344a2SDavid du Colombier 			if(na) {
142101a344a2SDavid du Colombier 				na = cwrecur(cw, na, j, tag1, qp);
142201a344a2SDavid du Colombier 				if(na) {
142301a344a2SDavid du Colombier 					((Off *)p->iobuf)[i] = na;
142401a344a2SDavid du Colombier 					p->flags |= Bmod;
142501a344a2SDavid du Colombier 				}
142601a344a2SDavid du Colombier 			}
142701a344a2SDavid du Colombier 		}
142801a344a2SDavid du Colombier 		break;
142901a344a2SDavid du Colombier 	}
143001a344a2SDavid du Colombier 	na = split(cw, p, addr);
143101a344a2SDavid du Colombier 	cw->depth--;
143201a344a2SDavid du Colombier 	if(na && shouldstop) {
143301a344a2SDavid du Colombier 		if(cw->falsehits < 10)
143401a344a2SDavid du Colombier 			print("shouldstop %lld %lld t=%s %s\n",
143501a344a2SDavid du Colombier 				(Wideoff)addr, (Wideoff)na,
143601a344a2SDavid du Colombier 				tagnames[tag], cw->name);
143701a344a2SDavid du Colombier 		cw->falsehits++;
143801a344a2SDavid du Colombier 	}
143901a344a2SDavid du Colombier 	return na;
144001a344a2SDavid du Colombier }
144101a344a2SDavid du Colombier 
144201a344a2SDavid du Colombier Timet	nextdump(Timet t);
144301a344a2SDavid du Colombier 
144401a344a2SDavid du Colombier void
cfsdump(Filsys * fs)144501a344a2SDavid du Colombier cfsdump(Filsys *fs)
144601a344a2SDavid du Colombier {
144701a344a2SDavid du Colombier 	long m, n, i;
144801a344a2SDavid du Colombier 	Off orba, rba, oroa, roa, sba, a;
144901a344a2SDavid du Colombier 	Timet tim;
145001a344a2SDavid du Colombier 	char tstr[20];
145101a344a2SDavid du Colombier 	Iobuf *pr, *p1, *p;
145201a344a2SDavid du Colombier 	Dentry *dr, *d1, *d;
145301a344a2SDavid du Colombier 	Cache *h;
145401a344a2SDavid du Colombier 	Superb *s;
145501a344a2SDavid du Colombier 	Cw *cw;
145601a344a2SDavid du Colombier 
145701a344a2SDavid du Colombier 	if(fs->dev->type != Devcw) {
145801a344a2SDavid du Colombier 		print("cant dump; not cw device: %Z\n", fs->dev);
145901a344a2SDavid du Colombier 		return;
146001a344a2SDavid du Colombier 	}
146101a344a2SDavid du Colombier 	cw = fs->dev->private;
146201a344a2SDavid du Colombier 	if(cw == 0) {
146301a344a2SDavid du Colombier 		print("cant dump: has not been inited: %Z\n", fs->dev);
146401a344a2SDavid du Colombier 		return;
146501a344a2SDavid du Colombier 	}
146601a344a2SDavid du Colombier 
146701a344a2SDavid du Colombier 	tim = toytime();
146801a344a2SDavid du Colombier 	wlock(&mainlock);		/* dump */
146901a344a2SDavid du Colombier 
147001a344a2SDavid du Colombier 	/*
147101a344a2SDavid du Colombier 	 * set up static structure
147201a344a2SDavid du Colombier 	 * with frequent variables
147301a344a2SDavid du Colombier 	 */
147401a344a2SDavid du Colombier 	cw->ndump = 0;
147501a344a2SDavid du Colombier 	cw->name[0] = 0;
147601a344a2SDavid du Colombier 	cw->depth = 0;
147701a344a2SDavid du Colombier 
147801a344a2SDavid du Colombier 	/*
147901a344a2SDavid du Colombier 	 * cw root
148001a344a2SDavid du Colombier 	 */
148101a344a2SDavid du Colombier 	sync("before dump");
148201a344a2SDavid du Colombier 	cw->fsize = cwsize(cw->dev);
148301a344a2SDavid du Colombier 	orba = cwraddr(cw->dev);
148401a344a2SDavid du Colombier 	print("cwroot %lld", (Wideoff)orba);
148501a344a2SDavid du Colombier 	cons.noage = 1;
148601a344a2SDavid du Colombier 	cw->all = cw->allflag;
148701a344a2SDavid du Colombier 	rba = cwrecur(cw, orba, Tsuper, 0, QPROOT);
148801a344a2SDavid du Colombier 	if(rba == 0)
148901a344a2SDavid du Colombier 		rba = orba;
149001a344a2SDavid du Colombier 	print("->%lld\n", (Wideoff)rba);
149101a344a2SDavid du Colombier 	sync("after cw");
149201a344a2SDavid du Colombier 
149301a344a2SDavid du Colombier 	/*
149401a344a2SDavid du Colombier 	 * partial super block
149501a344a2SDavid du Colombier 	 */
149601a344a2SDavid du Colombier 	p = getbuf(cw->dev, cwsaddr(cw->dev), Brd|Bmod|Bimm);
149701a344a2SDavid du Colombier 	s = (Superb*)p->iobuf;
149801a344a2SDavid du Colombier 	s->fsize = cw->fsize;
149901a344a2SDavid du Colombier 	s->cwraddr = rba;
150001a344a2SDavid du Colombier 	putbuf(p);
150101a344a2SDavid du Colombier 
150201a344a2SDavid du Colombier 	/*
150301a344a2SDavid du Colombier 	 * partial cache block
150401a344a2SDavid du Colombier 	 */
150501a344a2SDavid du Colombier 	p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bimm|Bres);
150601a344a2SDavid du Colombier 	h = (Cache*)p->iobuf;
150701a344a2SDavid du Colombier 	h->fsize = cw->fsize;
150801a344a2SDavid du Colombier 	h->cwraddr = rba;
150901a344a2SDavid du Colombier 	putbuf(p);
151001a344a2SDavid du Colombier 
151101a344a2SDavid du Colombier 	/*
151201a344a2SDavid du Colombier 	 * ro root
151301a344a2SDavid du Colombier 	 */
151401a344a2SDavid du Colombier 	oroa = cwraddr(cw->rodev);
151501a344a2SDavid du Colombier 	pr = getbuf(cw->dev, oroa, Brd|Bmod);
151601a344a2SDavid du Colombier 	dr = getdir(pr, 0);
151701a344a2SDavid du Colombier 
151801a344a2SDavid du Colombier 	datestr(tstr, time(nil));	/* tstr = "yyyymmdd" */
151901a344a2SDavid du Colombier 	n = 0;
152001a344a2SDavid du Colombier 	for(a=0;; a++) {
152101a344a2SDavid du Colombier 		p1 = dnodebuf(pr, dr, a, Tdir, 0);
152201a344a2SDavid du Colombier 		if(!p1)
152301a344a2SDavid du Colombier 			goto bad;
152401a344a2SDavid du Colombier 		n++;
152501a344a2SDavid du Colombier 		for(i=0; i<DIRPERBUF; i++) {
152601a344a2SDavid du Colombier 			d1 = getdir(p1, i);
152701a344a2SDavid du Colombier 			if(!d1)
152801a344a2SDavid du Colombier 				goto bad;
152901a344a2SDavid du Colombier 			if(!(d1->mode & DALLOC))
153001a344a2SDavid du Colombier 				goto found1;
153101a344a2SDavid du Colombier 			if(!memcmp(d1->name, tstr, 4))
153201a344a2SDavid du Colombier 				goto found2;	/* found entry */
153301a344a2SDavid du Colombier 		}
153401a344a2SDavid du Colombier 		putbuf(p1);
153501a344a2SDavid du Colombier 	}
153601a344a2SDavid du Colombier 
153701a344a2SDavid du Colombier 	/*
153801a344a2SDavid du Colombier 	 * no year directory, create one
153901a344a2SDavid du Colombier 	 */
154001a344a2SDavid du Colombier found1:
154101a344a2SDavid du Colombier 	p = getbuf(cw->dev, rba, Brd);
154201a344a2SDavid du Colombier 	d = getdir(p, 0);
154301a344a2SDavid du Colombier 	d1->qid = d->qid;
154401a344a2SDavid du Colombier 	d1->qid.version += n;
154501a344a2SDavid du Colombier 	memmove(d1->name, tstr, 4);
154601a344a2SDavid du Colombier 	d1->mode = d->mode;
154701a344a2SDavid du Colombier 	d1->uid = d->uid;
154801a344a2SDavid du Colombier 	d1->gid = d->gid;
154901a344a2SDavid du Colombier 	putbuf(p);
155001a344a2SDavid du Colombier 	accessdir(p1, d1, FWRITE, 0);
155101a344a2SDavid du Colombier 
155201a344a2SDavid du Colombier 	/*
155301a344a2SDavid du Colombier 	 * put mmdd[count] in year directory
155401a344a2SDavid du Colombier 	 */
155501a344a2SDavid du Colombier found2:
155601a344a2SDavid du Colombier 	accessdir(p1, d1, FREAD, 0);
155701a344a2SDavid du Colombier 	putbuf(pr);
155801a344a2SDavid du Colombier 	pr = p1;
155901a344a2SDavid du Colombier 	dr = d1;
156001a344a2SDavid du Colombier 
156101a344a2SDavid du Colombier 	n = 0;
156201a344a2SDavid du Colombier 	m = 0;
156301a344a2SDavid du Colombier 	for(a=0;; a++) {
156401a344a2SDavid du Colombier 		p1 = dnodebuf(pr, dr, a, Tdir, 0);
156501a344a2SDavid du Colombier 		if(!p1)
156601a344a2SDavid du Colombier 			goto bad;
156701a344a2SDavid du Colombier 		n++;
156801a344a2SDavid du Colombier 		for(i=0; i<DIRPERBUF; i++) {
156901a344a2SDavid du Colombier 			d1 = getdir(p1, i);
157001a344a2SDavid du Colombier 			if(!d1)
157101a344a2SDavid du Colombier 				goto bad;
157201a344a2SDavid du Colombier 			if(!(d1->mode & DALLOC))
157301a344a2SDavid du Colombier 				goto found;
157401a344a2SDavid du Colombier 			if(!memcmp(d1->name, tstr+4, 4))
157501a344a2SDavid du Colombier 				m++;
157601a344a2SDavid du Colombier 		}
157701a344a2SDavid du Colombier 		putbuf(p1);
157801a344a2SDavid du Colombier 	}
157901a344a2SDavid du Colombier 
158001a344a2SDavid du Colombier 	/*
158101a344a2SDavid du Colombier 	 * empty slot put in root
158201a344a2SDavid du Colombier 	 */
158301a344a2SDavid du Colombier found:
158401a344a2SDavid du Colombier 	if(m)	/* how many dumps this date */
158501a344a2SDavid du Colombier 		sprint(tstr+8, "%ld", m);
158601a344a2SDavid du Colombier 
158701a344a2SDavid du Colombier 	p = getbuf(cw->dev, rba, Brd);
158801a344a2SDavid du Colombier 	d = getdir(p, 0);
158901a344a2SDavid du Colombier 	*d1 = *d;				/* qid is QPROOT */
159001a344a2SDavid du Colombier 	putbuf(p);
159101a344a2SDavid du Colombier 	strcpy(d1->name, tstr+4);
159201a344a2SDavid du Colombier 	d1->qid.version += n;
159301a344a2SDavid du Colombier 	accessdir(p1, d1, FWRITE, 0);
159401a344a2SDavid du Colombier 	putbuf(p1);
159501a344a2SDavid du Colombier 	putbuf(pr);
159601a344a2SDavid du Colombier 
159701a344a2SDavid du Colombier 	cw->fsize = cwsize(cw->dev);
159801a344a2SDavid du Colombier 	oroa = cwraddr(cw->rodev);		/* probably redundant */
159901a344a2SDavid du Colombier 	print("roroot %lld", (Wideoff)oroa);
160001a344a2SDavid du Colombier 
160101a344a2SDavid du Colombier 	cons.noage = 0;
160201a344a2SDavid du Colombier 	cw->all = 0;
160301a344a2SDavid du Colombier 	roa = cwrecur(cw, oroa, Tsuper, 0, QPROOT);
160401a344a2SDavid du Colombier 	if(roa == 0) {
160501a344a2SDavid du Colombier 		print("[same]");
160601a344a2SDavid du Colombier 		roa = oroa;
160701a344a2SDavid du Colombier 	}
160801a344a2SDavid du Colombier 	print("->%lld /%.4s/%s\n", (Wideoff)roa, tstr, tstr+4);
160901a344a2SDavid du Colombier 	sync("after ro");
161001a344a2SDavid du Colombier 
161101a344a2SDavid du Colombier 	/*
161201a344a2SDavid du Colombier 	 * final super block
161301a344a2SDavid du Colombier 	 */
161401a344a2SDavid du Colombier 	a = cwsaddr(cw->dev);
161501a344a2SDavid du Colombier 	print("sblock %lld", (Wideoff)a);
161601a344a2SDavid du Colombier 	p = getbuf(cw->dev, a, Brd|Bmod|Bimm);
161701a344a2SDavid du Colombier 	s = (Superb*)p->iobuf;
161801a344a2SDavid du Colombier 	s->last = a;
161901a344a2SDavid du Colombier 	sba = s->next;
162001a344a2SDavid du Colombier 	s->next = cw->fsize;
162101a344a2SDavid du Colombier 	cw->fsize++;
162201a344a2SDavid du Colombier 	s->fsize = cw->fsize;
162301a344a2SDavid du Colombier 	s->roraddr = roa;
162401a344a2SDavid du Colombier 
162501a344a2SDavid du Colombier 	cwio(cw->dev, sba, 0, Ogrow);
162601a344a2SDavid du Colombier 	cwio(cw->dev, sba, p->iobuf, Owrite);
162701a344a2SDavid du Colombier 	cwio(cw->dev, sba, 0, Odump);
162801a344a2SDavid du Colombier 	print("->%lld (->%lld)\n", (Wideoff)sba, (Wideoff)s->next);
162901a344a2SDavid du Colombier 
163001a344a2SDavid du Colombier 	putbuf(p);
163101a344a2SDavid du Colombier 
163201a344a2SDavid du Colombier 	/*
163301a344a2SDavid du Colombier 	 * final cache block
163401a344a2SDavid du Colombier 	 */
163501a344a2SDavid du Colombier 	p = getbuf(cw->cdev, CACHE_ADDR, Brd|Bmod|Bimm|Bres);
163601a344a2SDavid du Colombier 	h = (Cache*)p->iobuf;
163701a344a2SDavid du Colombier 	h->fsize = cw->fsize;
163801a344a2SDavid du Colombier 	h->roraddr = roa;
163901a344a2SDavid du Colombier 	h->sbaddr = sba;
164001a344a2SDavid du Colombier 	putbuf(p);
164101a344a2SDavid du Colombier 
164201a344a2SDavid du Colombier 	rewalk(cw);
164301a344a2SDavid du Colombier 	sync("all done");
164401a344a2SDavid du Colombier 
164501a344a2SDavid du Colombier 	print("%lld blocks queued for worm\n", (Wideoff)cw->ndump);
164601a344a2SDavid du Colombier 	print("%lld falsehits\n", (Wideoff)cw->falsehits);
164701a344a2SDavid du Colombier 	cw->nodump = 0;
164801a344a2SDavid du Colombier 
164901a344a2SDavid du Colombier 	/*
165001a344a2SDavid du Colombier 	 * extend all of the locks
165101a344a2SDavid du Colombier 	 */
165201a344a2SDavid du Colombier 	tim = toytime() - tim;
165301a344a2SDavid du Colombier 	for(i=0; i<NTLOCK; i++)
165401a344a2SDavid du Colombier 		if(tlocks[i].time > 0)
165501a344a2SDavid du Colombier 			tlocks[i].time += tim;
165601a344a2SDavid du Colombier 
165701a344a2SDavid du Colombier 	wunlock(&mainlock);
165801a344a2SDavid du Colombier 	nextdump(time(nil));
165901a344a2SDavid du Colombier 	return;
166001a344a2SDavid du Colombier 
166101a344a2SDavid du Colombier bad:
166201a344a2SDavid du Colombier 	panic("dump: bad");
166301a344a2SDavid du Colombier }
166401a344a2SDavid du Colombier 
166501a344a2SDavid du Colombier void
mvstates(Device * dev,int s1,int s2,int side)166601a344a2SDavid du Colombier mvstates(Device *dev, int s1, int s2, int side)
166701a344a2SDavid du Colombier {
166801a344a2SDavid du Colombier 	Iobuf *p, *cb;
166901a344a2SDavid du Colombier 	Cache *h;
167001a344a2SDavid du Colombier 	Bucket *b;
167101a344a2SDavid du Colombier 	Centry *c, *ce;
167201a344a2SDavid du Colombier 	Off m, lo, hi, msize, maddr;
167301a344a2SDavid du Colombier 	Cw *cw;
167401a344a2SDavid du Colombier 
167501a344a2SDavid du Colombier 	cw = dev->private;
167601a344a2SDavid du Colombier 	lo = 0;
167701a344a2SDavid du Colombier 	hi = lo + devsize(dev->cw.w);	/* size of all sides totalled */
167801a344a2SDavid du Colombier 	if(side >= 0) {
167901a344a2SDavid du Colombier 		/* operate on only a single disc side */
168001a344a2SDavid du Colombier 		Sidestarts ss;
168101a344a2SDavid du Colombier 
168201a344a2SDavid du Colombier 		wormsidestarts(dev, side, &ss);
168301a344a2SDavid du Colombier 		lo = ss.sstart;
168401a344a2SDavid du Colombier 		hi = ss.s1start;
168501a344a2SDavid du Colombier 	}
168601a344a2SDavid du Colombier 	cb = getbuf(cw->cdev, CACHE_ADDR, Brd|Bres);
168701a344a2SDavid du Colombier 	if(!cb || checktag(cb, Tcache, QPSUPER))
168801a344a2SDavid du Colombier 		panic("cwstats: checktag c bucket");
168901a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
169001a344a2SDavid du Colombier 	msize = h->msize;
169101a344a2SDavid du Colombier 	maddr = h->maddr;
169201a344a2SDavid du Colombier 	putbuf(cb);
169301a344a2SDavid du Colombier 
169401a344a2SDavid du Colombier 	for(m=0; m<msize; m++) {
169501a344a2SDavid du Colombier 		p = getbuf(cw->cdev, maddr + m/BKPERBLK, Brd|Bmod);
169601a344a2SDavid du Colombier 		if(!p || checktag(p, Tbuck, maddr + m/BKPERBLK))
169701a344a2SDavid du Colombier 			panic("cwtest: checktag c bucket");
169801a344a2SDavid du Colombier 		b = (Bucket*)p->iobuf + m%BKPERBLK;
169901a344a2SDavid du Colombier 		ce = b->entry + CEPERBK;
170001a344a2SDavid du Colombier 		for(c=b->entry; c<ce; c++)
170101a344a2SDavid du Colombier 			if(c->state == s1 && c->waddr >= lo && c->waddr < hi)
170201a344a2SDavid du Colombier 				c->state = s2;
170301a344a2SDavid du Colombier 		putbuf(p);
170401a344a2SDavid du Colombier 	}
170501a344a2SDavid du Colombier }
170601a344a2SDavid du Colombier 
170701a344a2SDavid du Colombier void
prchain(Device * dev,Off m,int flg)170801a344a2SDavid du Colombier prchain(Device *dev, Off m, int flg)
170901a344a2SDavid du Colombier {
171001a344a2SDavid du Colombier 	Iobuf *p;
171101a344a2SDavid du Colombier 	Superb *s;
171201a344a2SDavid du Colombier 
171301a344a2SDavid du Colombier 	if(m == 0) {
171401a344a2SDavid du Colombier 		if(flg)
171501a344a2SDavid du Colombier 			m = cwsaddr(dev);
171601a344a2SDavid du Colombier 		else
171701a344a2SDavid du Colombier 			m = getstartsb(dev);
171801a344a2SDavid du Colombier 	}
171901a344a2SDavid du Colombier 	p = getbuf(devnone, Cwxx2, 0);
172001a344a2SDavid du Colombier 	s = (Superb*)p->iobuf;
172101a344a2SDavid du Colombier 	for(;;) {
172201a344a2SDavid du Colombier 		memset(p->iobuf, 0, RBUFSIZE);
172301a344a2SDavid du Colombier 		if(devread(WDEV(dev), m, p->iobuf) ||
172401a344a2SDavid du Colombier 		   checktag(p, Tsuper, QPSUPER))
172501a344a2SDavid du Colombier 			break;
172601a344a2SDavid du Colombier 		if(flg) {
172701a344a2SDavid du Colombier 			print("dump %lld is good; %lld prev\n", (Wideoff)m,
172801a344a2SDavid du Colombier 				(Wideoff)s->last);
172901a344a2SDavid du Colombier 			print("\t%lld cwroot; %lld roroot\n",
173001a344a2SDavid du Colombier 				(Wideoff)s->cwraddr, (Wideoff)s->roraddr);
173101a344a2SDavid du Colombier 			if(m <= s->last)
173201a344a2SDavid du Colombier 				break;
173301a344a2SDavid du Colombier 			m = s->last;
173401a344a2SDavid du Colombier 		} else {
173501a344a2SDavid du Colombier 			print("dump %lld is good; %lld next\n", (Wideoff)m,
173601a344a2SDavid du Colombier 				(Wideoff)s->next);
173701a344a2SDavid du Colombier 			print("\t%lld cwroot; %lld roroot\n",
173801a344a2SDavid du Colombier 				(Wideoff)s->cwraddr, (Wideoff)s->roraddr);
173901a344a2SDavid du Colombier 			if(m >= s->next)
174001a344a2SDavid du Colombier 				break;
174101a344a2SDavid du Colombier 			m = s->next;
174201a344a2SDavid du Colombier 		}
174301a344a2SDavid du Colombier 	}
174401a344a2SDavid du Colombier 	putbuf(p);
174501a344a2SDavid du Colombier }
174601a344a2SDavid du Colombier 
174701a344a2SDavid du Colombier void
touchsb(Device * dev)174801a344a2SDavid du Colombier touchsb(Device *dev)
174901a344a2SDavid du Colombier {
175001a344a2SDavid du Colombier 	Iobuf *p;
175101a344a2SDavid du Colombier 	Off m;
175201a344a2SDavid du Colombier 
175301a344a2SDavid du Colombier 	m = cwsaddr(dev);
175401a344a2SDavid du Colombier 	p = getbuf(devnone, Cwxx2, 0);
175501a344a2SDavid du Colombier 
175601a344a2SDavid du Colombier 	memset(p->iobuf, 0, RBUFSIZE);
175701a344a2SDavid du Colombier 	if(devread(WDEV(dev), m, p->iobuf) ||
175801a344a2SDavid du Colombier 	   checktag(p, Tsuper, QPSUPER))
175901a344a2SDavid du Colombier 		print("%Z block %lld WORM SUPER BLOCK READ FAILED\n",
176001a344a2SDavid du Colombier 			WDEV(dev), (Wideoff)m);
176101a344a2SDavid du Colombier 	else
176201a344a2SDavid du Colombier 		print("%Z touch superblock %lld\n", WDEV(dev), (Wideoff)m);
176301a344a2SDavid du Colombier 	putbuf(p);
176401a344a2SDavid du Colombier }
176501a344a2SDavid du Colombier 
176601a344a2SDavid du Colombier void
storesb(Device * dev,Off last,int doit)176701a344a2SDavid du Colombier storesb(Device *dev, Off last, int doit)
176801a344a2SDavid du Colombier {
176901a344a2SDavid du Colombier 	Iobuf *ph, *ps;
177001a344a2SDavid du Colombier 	Cache *h;
177101a344a2SDavid du Colombier 	Superb *s;
177201a344a2SDavid du Colombier 	Off sbaddr, qidgen;
177301a344a2SDavid du Colombier 
177401a344a2SDavid du Colombier 	sbaddr = cwsaddr(dev);
177501a344a2SDavid du Colombier 
177601a344a2SDavid du Colombier 	ps = getbuf(devnone, Cwxx2, 0);
177701a344a2SDavid du Colombier 	if(!ps) {
177801a344a2SDavid du Colombier 		print("sbstore: getbuf\n");
177901a344a2SDavid du Colombier 		return;
178001a344a2SDavid du Colombier 	}
178101a344a2SDavid du Colombier 
178201a344a2SDavid du Colombier 	/*
178301a344a2SDavid du Colombier 	 * try to read last sb
178401a344a2SDavid du Colombier 	 */
178501a344a2SDavid du Colombier 	memset(ps->iobuf, 0, RBUFSIZE);
178601a344a2SDavid du Colombier 	if(devread(WDEV(dev), last, ps->iobuf) ||
178701a344a2SDavid du Colombier 	   checktag(ps, Tsuper, QPSUPER))
178801a344a2SDavid du Colombier 		print("read last failed\n");
178901a344a2SDavid du Colombier 	else
179001a344a2SDavid du Colombier 		print("read last succeeded\n");
179101a344a2SDavid du Colombier 
179201a344a2SDavid du Colombier 	s = (Superb*)ps->iobuf;
179301a344a2SDavid du Colombier 	qidgen = s->qidgen;
179401a344a2SDavid du Colombier 	if(qidgen == 0)
179501a344a2SDavid du Colombier 		qidgen = 0x31415;
179601a344a2SDavid du Colombier 	qidgen += 1000;
179701a344a2SDavid du Colombier 	if(s->next != sbaddr)
179801a344a2SDavid du Colombier 		print("next(last) is not sbaddr %lld %lld\n",
179901a344a2SDavid du Colombier 			(Wideoff)s->next, (Wideoff)sbaddr);
180001a344a2SDavid du Colombier 	else
180101a344a2SDavid du Colombier 		print("next(last) is sbaddr\n");
180201a344a2SDavid du Colombier 
180301a344a2SDavid du Colombier 	/*
180401a344a2SDavid du Colombier 	 * read cached superblock
180501a344a2SDavid du Colombier 	 */
180601a344a2SDavid du Colombier 	ph = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
180701a344a2SDavid du Colombier 	if(!ph || checktag(ph, Tcache, QPSUPER)) {
180801a344a2SDavid du Colombier 		print("cwstats: checktag c bucket\n");
180901a344a2SDavid du Colombier 		if(ph)
181001a344a2SDavid du Colombier 			putbuf(ph);
181101a344a2SDavid du Colombier 		putbuf(ps);
181201a344a2SDavid du Colombier 		return;
181301a344a2SDavid du Colombier 	} else
181401a344a2SDavid du Colombier 		print("read cached sb succeeded\n");
181501a344a2SDavid du Colombier 
181601a344a2SDavid du Colombier 	h = (Cache*)ph->iobuf;
181701a344a2SDavid du Colombier 
181801a344a2SDavid du Colombier 	memset(ps->iobuf, 0, RBUFSIZE);
181901a344a2SDavid du Colombier 	settag(ps, Tsuper, QPSUPER);
182001a344a2SDavid du Colombier 	ps->flags = 0;
182101a344a2SDavid du Colombier 	s = (Superb*)ps->iobuf;
182201a344a2SDavid du Colombier 
182301a344a2SDavid du Colombier 	s->cwraddr = h->cwraddr;
182401a344a2SDavid du Colombier 	s->roraddr = h->roraddr;
182501a344a2SDavid du Colombier 	s->fsize = h->fsize;
182601a344a2SDavid du Colombier 	s->fstart = 2;
182701a344a2SDavid du Colombier 	s->last = last;
182801a344a2SDavid du Colombier 	s->next = h->roraddr+1;
182901a344a2SDavid du Colombier 
183001a344a2SDavid du Colombier 	s->qidgen = qidgen;
183101a344a2SDavid du Colombier 	putbuf(ph);
183201a344a2SDavid du Colombier 
183301a344a2SDavid du Colombier 	if(s->fsize-1 != s->next ||
183401a344a2SDavid du Colombier 	   s->fsize-2 != s->roraddr ||
183501a344a2SDavid du Colombier 	   s->fsize-5 != s->cwraddr) {
183601a344a2SDavid du Colombier 		print("addrs not in relationship %lld %lld %lld %lld\n",
183701a344a2SDavid du Colombier 			(Wideoff)s->cwraddr, (Wideoff)s->roraddr,
183801a344a2SDavid du Colombier 			(Wideoff)s->next, (Wideoff)s->fsize);
183901a344a2SDavid du Colombier 		putbuf(ps);
184001a344a2SDavid du Colombier 		return;
184101a344a2SDavid du Colombier 	} else
184201a344a2SDavid du Colombier 		print("addresses in relation\n");
184301a344a2SDavid du Colombier 
184401a344a2SDavid du Colombier 	if(doit)
184501a344a2SDavid du Colombier 	if(devwrite(WDEV(dev), sbaddr, ps->iobuf))
184601a344a2SDavid du Colombier 		print("%Z block %lld WORM SUPER BLOCK WRITE FAILED\n",
184701a344a2SDavid du Colombier 			WDEV(dev), (Wideoff)sbaddr);
184801a344a2SDavid du Colombier 	ps->flags = 0;
184901a344a2SDavid du Colombier 	putbuf(ps);
185001a344a2SDavid du Colombier }
185101a344a2SDavid du Colombier 
185201a344a2SDavid du Colombier void
savecache(Device * dev)185301a344a2SDavid du Colombier savecache(Device *dev)
185401a344a2SDavid du Colombier {
185501a344a2SDavid du Colombier 	Iobuf *p, *cb;
185601a344a2SDavid du Colombier 	Cache *h;
185701a344a2SDavid du Colombier 	Bucket *b;
185801a344a2SDavid du Colombier 	Centry *c, *ce;
185901a344a2SDavid du Colombier 	long n, left;
186001a344a2SDavid du Colombier 	Off m, maddr, msize, *longp, nbyte;
186101a344a2SDavid du Colombier 	Device *cdev;
186201a344a2SDavid du Colombier 
186301a344a2SDavid du Colombier 	if(walkto("/adm/cache") || con_open(FID2, OWRITE|OTRUNC)) {
186401a344a2SDavid du Colombier 		print("cant open /adm/cache\n");
186501a344a2SDavid du Colombier 		return;
186601a344a2SDavid du Colombier 	}
186701a344a2SDavid du Colombier 	cdev = CDEV(dev);
186801a344a2SDavid du Colombier 	cb = getbuf(cdev, CACHE_ADDR, Brd|Bres);
186901a344a2SDavid du Colombier 	if(!cb || checktag(cb, Tcache, QPSUPER))
187001a344a2SDavid du Colombier 		panic("savecache: checktag c bucket");
187101a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
187201a344a2SDavid du Colombier 	msize = h->msize;
187301a344a2SDavid du Colombier 	maddr = h->maddr;
187401a344a2SDavid du Colombier 	putbuf(cb);
187501a344a2SDavid du Colombier 
187601a344a2SDavid du Colombier 	n = BUFSIZE;			/* calculate write size */
187701a344a2SDavid du Colombier 	if(n > MAXDAT)
187801a344a2SDavid du Colombier 		n = MAXDAT;
187901a344a2SDavid du Colombier 
188001a344a2SDavid du Colombier 	cb = getbuf(devnone, Cwxx4, 0);
188101a344a2SDavid du Colombier 	longp = (Off *)cb->iobuf;
188201a344a2SDavid du Colombier 	left = n/sizeof(Off);
188301a344a2SDavid du Colombier 	cons.offset = 0;
188401a344a2SDavid du Colombier 
188501a344a2SDavid du Colombier 	for(m=0; m<msize; m++) {
188601a344a2SDavid du Colombier 		if(left < BKPERBLK) {
188701a344a2SDavid du Colombier 			nbyte = (n/sizeof(Off) - left) * sizeof(Off);
188801a344a2SDavid du Colombier 			con_write(FID2, cb->iobuf, cons.offset, nbyte);
188901a344a2SDavid du Colombier 			cons.offset += nbyte;
189001a344a2SDavid du Colombier 			longp = (Off *)cb->iobuf;
189101a344a2SDavid du Colombier 			left = n/sizeof(Off);
189201a344a2SDavid du Colombier 		}
189301a344a2SDavid du Colombier 		p = getbuf(cdev, maddr + m/BKPERBLK, Brd);
189401a344a2SDavid du Colombier 		if(!p || checktag(p, Tbuck, maddr + m/BKPERBLK))
189501a344a2SDavid du Colombier 			panic("cwtest: checktag c bucket");
189601a344a2SDavid du Colombier 		b = (Bucket*)p->iobuf + m%BKPERBLK;
189701a344a2SDavid du Colombier 		ce = b->entry + CEPERBK;
189801a344a2SDavid du Colombier 		for(c = b->entry; c < ce; c++)
189901a344a2SDavid du Colombier 			if(c->state == Cread) {
190001a344a2SDavid du Colombier 				*longp++ = c->waddr;
190101a344a2SDavid du Colombier 				left--;
190201a344a2SDavid du Colombier 			}
190301a344a2SDavid du Colombier 		putbuf(p);
190401a344a2SDavid du Colombier 	}
190501a344a2SDavid du Colombier 	nbyte = (n/sizeof(Off) - left) * sizeof(Off);
190601a344a2SDavid du Colombier 	con_write(FID2, cb->iobuf, cons.offset, nbyte);
190701a344a2SDavid du Colombier 	putbuf(cb);
190801a344a2SDavid du Colombier }
190901a344a2SDavid du Colombier 
191001a344a2SDavid du Colombier void
loadcache(Device * dev,int dskno)191101a344a2SDavid du Colombier loadcache(Device *dev, int dskno)
191201a344a2SDavid du Colombier {
191301a344a2SDavid du Colombier 	Iobuf *p, *cb;
191401a344a2SDavid du Colombier 	Off m, nbyte, *longp, count;
191501a344a2SDavid du Colombier 	Sidestarts ss;
191601a344a2SDavid du Colombier 
191701a344a2SDavid du Colombier 	if(walkto("/adm/cache") || con_open(FID2, OREAD)) {
191801a344a2SDavid du Colombier 		print("cant open /adm/cache\n");
191901a344a2SDavid du Colombier 		return;
192001a344a2SDavid du Colombier 	}
192101a344a2SDavid du Colombier 
192201a344a2SDavid du Colombier 	cb = getbuf(devnone, Cwxx4, 0);
192301a344a2SDavid du Colombier 	cons.offset = 0;
192401a344a2SDavid du Colombier 	count = 0;
192501a344a2SDavid du Colombier 
192601a344a2SDavid du Colombier 	if (dskno >= 0)
192701a344a2SDavid du Colombier 		wormsidestarts(dev, dskno, &ss);
192801a344a2SDavid du Colombier 	for(;;) {
192901a344a2SDavid du Colombier 		memset(cb->iobuf, 0, BUFSIZE);
193001a344a2SDavid du Colombier 		nbyte = con_read(FID2, cb->iobuf, cons.offset, 100) / sizeof(Off);
193101a344a2SDavid du Colombier 		if(nbyte <= 0)
193201a344a2SDavid du Colombier 			break;
193301a344a2SDavid du Colombier 		cons.offset += nbyte * sizeof(Off);
193401a344a2SDavid du Colombier 		longp = (Off *)cb->iobuf;
193501a344a2SDavid du Colombier 		while(nbyte > 0) {
193601a344a2SDavid du Colombier 			m = *longp++;
193701a344a2SDavid du Colombier 			nbyte--;
193801a344a2SDavid du Colombier 			if(m == 0)
193901a344a2SDavid du Colombier 				continue;
194001a344a2SDavid du Colombier 			/* if given a diskno, restrict to just that disc side */
194101a344a2SDavid du Colombier 			if(dskno < 0 || m >= ss.sstart && m < ss.s1start) {
194201a344a2SDavid du Colombier 				p = getbuf(dev, m, Brd);
194301a344a2SDavid du Colombier 				if(p)
194401a344a2SDavid du Colombier 					putbuf(p);
194501a344a2SDavid du Colombier 				count++;
194601a344a2SDavid du Colombier 			}
194701a344a2SDavid du Colombier 		}
194801a344a2SDavid du Colombier 	}
194901a344a2SDavid du Colombier 	putbuf(cb);
195001a344a2SDavid du Colombier 	print("%lld blocks loaded from worm %d\n", (Wideoff)count, dskno);
195101a344a2SDavid du Colombier }
195201a344a2SDavid du Colombier 
195301a344a2SDavid du Colombier void
morecache(Device * dev,int dskno,Off size)195401a344a2SDavid du Colombier morecache(Device *dev, int dskno, Off size)
195501a344a2SDavid du Colombier {
195601a344a2SDavid du Colombier 	Iobuf *p;
195701a344a2SDavid du Colombier 	Off m, ml, mh, mm, count;
195801a344a2SDavid du Colombier 	Cache *h;
195901a344a2SDavid du Colombier 	Sidestarts ss;
196001a344a2SDavid du Colombier 
196101a344a2SDavid du Colombier 	p = getbuf(CDEV(dev), CACHE_ADDR, Brd|Bres);
196201a344a2SDavid du Colombier 	if(!p || checktag(p, Tcache, QPSUPER))
196301a344a2SDavid du Colombier 		panic("savecache: checktag c bucket");
196401a344a2SDavid du Colombier 	h = (Cache*)p->iobuf;
196501a344a2SDavid du Colombier 	mm = h->wmax;
196601a344a2SDavid du Colombier 	putbuf(p);
196701a344a2SDavid du Colombier 
196801a344a2SDavid du Colombier 	wormsidestarts(dev, dskno, &ss);
196901a344a2SDavid du Colombier 	ml = ss.sstart;		/* start at beginning of disc side #dskno */
197001a344a2SDavid du Colombier 	mh = ml + size;
197101a344a2SDavid du Colombier 	if(mh > mm) {
197201a344a2SDavid du Colombier 		mh = mm;
197301a344a2SDavid du Colombier 		print("limited to %lld\n", (Wideoff)mh-ml);
197401a344a2SDavid du Colombier 	}
197501a344a2SDavid du Colombier 
197601a344a2SDavid du Colombier 	count = 0;
197701a344a2SDavid du Colombier 	for(m=ml; m < mh; m++) {
197801a344a2SDavid du Colombier 		p = getbuf(dev, m, Brd);
197901a344a2SDavid du Colombier 		if(p)
198001a344a2SDavid du Colombier 			putbuf(p);
198101a344a2SDavid du Colombier 		count++;
198201a344a2SDavid du Colombier 	}
198301a344a2SDavid du Colombier 	print("%lld blocks loaded from worm %d\n", (Wideoff)count, dskno);
198401a344a2SDavid du Colombier }
198501a344a2SDavid du Colombier 
198601a344a2SDavid du Colombier void
blockcmp(Device * dev,Off wa,Off ca)198701a344a2SDavid du Colombier blockcmp(Device *dev, Off wa, Off ca)
198801a344a2SDavid du Colombier {
198901a344a2SDavid du Colombier 	Iobuf *p1, *p2;
199001a344a2SDavid du Colombier 	int i, c;
199101a344a2SDavid du Colombier 
199201a344a2SDavid du Colombier 	p1 = getbuf(WDEV(dev), wa, Brd);
199301a344a2SDavid du Colombier 	if(!p1) {
199401a344a2SDavid du Colombier 		print("blockcmp: wdev error\n");
199501a344a2SDavid du Colombier 		return;
199601a344a2SDavid du Colombier 	}
199701a344a2SDavid du Colombier 
199801a344a2SDavid du Colombier 	p2 = getbuf(CDEV(dev), ca, Brd);
199901a344a2SDavid du Colombier 	if(!p2) {
200001a344a2SDavid du Colombier 		print("blockcmp: cdev error\n");
200101a344a2SDavid du Colombier 		putbuf(p1);
200201a344a2SDavid du Colombier 		return;
200301a344a2SDavid du Colombier 	}
200401a344a2SDavid du Colombier 
200501a344a2SDavid du Colombier 	c = 0;
200601a344a2SDavid du Colombier 	for(i=0; i<RBUFSIZE; i++)
200701a344a2SDavid du Colombier 		if(p1->iobuf[i] != p2->iobuf[i]) {
200801a344a2SDavid du Colombier 			print("%4d: %.2x %.2x\n",
200901a344a2SDavid du Colombier 				i,
201001a344a2SDavid du Colombier 				p1->iobuf[i]&0xff,
201101a344a2SDavid du Colombier 				p2->iobuf[i]&0xff);
201201a344a2SDavid du Colombier 			c++;
201301a344a2SDavid du Colombier 			if(c >= 10)
201401a344a2SDavid du Colombier 				break;
201501a344a2SDavid du Colombier 		}
201601a344a2SDavid du Colombier 
201701a344a2SDavid du Colombier 	if(c == 0)
201801a344a2SDavid du Colombier 		print("no error\n");
201901a344a2SDavid du Colombier 	putbuf(p1);
202001a344a2SDavid du Colombier 	putbuf(p2);
202101a344a2SDavid du Colombier }
202201a344a2SDavid du Colombier 
202301a344a2SDavid du Colombier void
wblock(Device * dev,Off addr)202401a344a2SDavid du Colombier wblock(Device *dev, Off addr)
202501a344a2SDavid du Colombier {
202601a344a2SDavid du Colombier 	Iobuf *p1;
202701a344a2SDavid du Colombier 	int i;
202801a344a2SDavid du Colombier 
202901a344a2SDavid du Colombier 	p1 = getbuf(dev, addr, Brd);
203001a344a2SDavid du Colombier 	if(p1) {
203101a344a2SDavid du Colombier 		i = devwrite(WDEV(dev), addr, p1->iobuf);
203201a344a2SDavid du Colombier 		print("i = %d\n", i);
203301a344a2SDavid du Colombier 		putbuf(p1);
203401a344a2SDavid du Colombier 	}
203501a344a2SDavid du Colombier }
203601a344a2SDavid du Colombier 
203701a344a2SDavid du Colombier void
cwtest(Device *)203801a344a2SDavid du Colombier cwtest(Device*)
203901a344a2SDavid du Colombier {
204001a344a2SDavid du Colombier }
204101a344a2SDavid du Colombier 
204201a344a2SDavid du Colombier #ifdef	XXX
204301a344a2SDavid du Colombier /* garbage to change sb size
204401a344a2SDavid du Colombier  * probably will need it someday
204501a344a2SDavid du Colombier  */
204601a344a2SDavid du Colombier 	fsz = number(0, 0, 10);
204701a344a2SDavid du Colombier 	count = 0;
204801a344a2SDavid du Colombier 	if(fsz == number(0, -1, 10))
204901a344a2SDavid du Colombier 		count = -1;		/* really do it */
205001a344a2SDavid du Colombier 	print("fsize = %ld\n", fsz);
205101a344a2SDavid du Colombier 	cdev = CDEV(dev);
205201a344a2SDavid du Colombier 	cb = getbuf(cdev, CACHE_ADDR, Brd|Bres);
205301a344a2SDavid du Colombier 	if(!cb || checktag(cb, Tcache, QPSUPER))
205401a344a2SDavid du Colombier 		panic("cwstats: checktag c bucket");
205501a344a2SDavid du Colombier 	h = (Cache*)cb->iobuf;
205601a344a2SDavid du Colombier 	for(m=0; m<h->msize; m++) {
205701a344a2SDavid du Colombier 		p = getbuf(cdev, h->maddr + m/BKPERBLK, Brd|Bmod);
205801a344a2SDavid du Colombier 		if(!p || checktag(p, Tbuck, h->maddr + m/BKPERBLK))
205901a344a2SDavid du Colombier 			panic("cwtest: checktag c bucket");
206001a344a2SDavid du Colombier 		b = (Bucket*)p->iobuf + m%BKPERBLK;
206101a344a2SDavid du Colombier 		ce = b->entry + CEPERBK;
206201a344a2SDavid du Colombier 		for(c=b->entry; c<ce; c++) {
206301a344a2SDavid du Colombier 			if(c->waddr < fsz)
206401a344a2SDavid du Colombier 				continue;
206501a344a2SDavid du Colombier 			if(count < 0) {
206601a344a2SDavid du Colombier 				c->state = Cnone;
206701a344a2SDavid du Colombier 				continue;
206801a344a2SDavid du Colombier 			}
206901a344a2SDavid du Colombier 			if(c->state != Cdirty)
207001a344a2SDavid du Colombier 				count++;
207101a344a2SDavid du Colombier 		}
207201a344a2SDavid du Colombier 		putbuf(p);
207301a344a2SDavid du Colombier 	}
207401a344a2SDavid du Colombier 	if(count < 0) {
207501a344a2SDavid du Colombier 		print("old cache hsize = %ld\n", h->fsize);
207601a344a2SDavid du Colombier 		h->fsize = fsz;
207701a344a2SDavid du Colombier 		cb->flags |= Bmod;
207801a344a2SDavid du Colombier 		p = getbuf(dev, h->sbaddr, Brd|Bmod);
207901a344a2SDavid du Colombier 		s = (Superb*)p->iobuf;
208001a344a2SDavid du Colombier 		print("old super hsize = %ld\n", s->fsize);
208101a344a2SDavid du Colombier 		s->fsize = fsz;
208201a344a2SDavid du Colombier 		putbuf(p);
208301a344a2SDavid du Colombier 	}
208401a344a2SDavid du Colombier 	putbuf(cb);
208501a344a2SDavid du Colombier 	print("count = %lld\n", (Wideoff)count);
208601a344a2SDavid du Colombier #endif
208701a344a2SDavid du Colombier 
208801a344a2SDavid du Colombier int
convstate(char * name)208901a344a2SDavid du Colombier convstate(char *name)
209001a344a2SDavid du Colombier {
209101a344a2SDavid du Colombier 	int i;
209201a344a2SDavid du Colombier 
209301a344a2SDavid du Colombier 	for(i=0; i<nelem(cwnames); i++)
209401a344a2SDavid du Colombier 		if(cwnames[i])
209501a344a2SDavid du Colombier 			if(strcmp(cwnames[i], name) == 0)
209601a344a2SDavid du Colombier 				return i;
209701a344a2SDavid du Colombier 	return -1;
209801a344a2SDavid du Colombier }
209901a344a2SDavid du Colombier 
210001a344a2SDavid du Colombier void
searchtag(Device * d,Off a,int tag,int n)210101a344a2SDavid du Colombier searchtag(Device *d, Off a, int tag, int n)
210201a344a2SDavid du Colombier {
210301a344a2SDavid du Colombier 	Iobuf *p;
210401a344a2SDavid du Colombier 	Tag *t;
210501a344a2SDavid du Colombier 	int i;
210601a344a2SDavid du Colombier 
210701a344a2SDavid du Colombier 	if(a == 0)
210801a344a2SDavid du Colombier 		a = getstartsb(d);
210901a344a2SDavid du Colombier 	p = getbuf(devnone, Cwxx2, 0);
211001a344a2SDavid du Colombier 	t = (Tag*)(p->iobuf+BUFSIZE);
211101a344a2SDavid du Colombier 	for(i=0; i<n; i++) {
211201a344a2SDavid du Colombier 		memset(p->iobuf, 0, RBUFSIZE);
211301a344a2SDavid du Colombier 		if(devread(WDEV(d), a+i, p->iobuf)) {
211401a344a2SDavid du Colombier 			if(n == 1000)
211501a344a2SDavid du Colombier 				break;
211601a344a2SDavid du Colombier 			continue;
211701a344a2SDavid du Colombier 		}
211801a344a2SDavid du Colombier 		if(t->tag == tag) {
211901a344a2SDavid du Colombier 			print("tag %d found at %Z %lld\n", tag, d, (Wideoff)a+i);
212001a344a2SDavid du Colombier 			break;
212101a344a2SDavid du Colombier 		}
212201a344a2SDavid du Colombier 	}
212301a344a2SDavid du Colombier 	putbuf(p);
212401a344a2SDavid du Colombier }
212501a344a2SDavid du Colombier 
212601a344a2SDavid du Colombier void
cmd_cwcmd(int argc,char * argv[])212701a344a2SDavid du Colombier cmd_cwcmd(int argc, char *argv[])
212801a344a2SDavid du Colombier {
212901a344a2SDavid du Colombier 	Device *dev;
213001a344a2SDavid du Colombier 	char *arg;
213101a344a2SDavid du Colombier 	char str[28];
213201a344a2SDavid du Colombier 	Off s1, s2, a, b, n;
213301a344a2SDavid du Colombier 	Cw *cw;
213401a344a2SDavid du Colombier 
213501a344a2SDavid du Colombier 	if(argc <= 1) {
213601a344a2SDavid du Colombier 		print("\tcwcmd mvstate state1 state2 [platter]\n");
213701a344a2SDavid du Colombier 		print("\tcwcmd prchain [start] [bakflg]\n");
213801a344a2SDavid du Colombier 		print("\tcwcmd searchtag [start] [tag] [blocks]\n");
213901a344a2SDavid du Colombier 		print("\tcwcmd touchsb\n");
214001a344a2SDavid du Colombier 		print("\tcwcmd savecache\n");
214101a344a2SDavid du Colombier 		print("\tcwcmd loadcache [dskno]\n");
214201a344a2SDavid du Colombier 		print("\tcwcmd morecache dskno [count]\n");
214301a344a2SDavid du Colombier 		print("\tcwcmd blockcmp wbno cbno\n");
214401a344a2SDavid du Colombier 		print("\tcwcmd startdump [01]\n");
214501a344a2SDavid du Colombier 		print("\tcwcmd acct\n");
214601a344a2SDavid du Colombier 		print("\tcwcmd clearacct\n");
214701a344a2SDavid du Colombier 		return;
214801a344a2SDavid du Colombier 	}
214901a344a2SDavid du Colombier 	arg = argv[1];
215001a344a2SDavid du Colombier 
215101a344a2SDavid du Colombier 	/*
215201a344a2SDavid du Colombier 	 * items not depend on a cw filesystem
215301a344a2SDavid du Colombier 	 */
215401a344a2SDavid du Colombier 	if(strcmp(arg, "acct") == 0) {
215501a344a2SDavid du Colombier 		for(a=0; a<nelem(growacct); a++) {
215601a344a2SDavid du Colombier 			b = growacct[a];
215701a344a2SDavid du Colombier 			if(b) {
215801a344a2SDavid du Colombier 				uidtostr(str, a, 1);
215901a344a2SDavid du Colombier 				print("%10lld %s\n",
216001a344a2SDavid du Colombier 					((Wideoff)b*ADDFREE*RBUFSIZE+500000)/1000000,
216101a344a2SDavid du Colombier 					str);
216201a344a2SDavid du Colombier 			}
216301a344a2SDavid du Colombier 		}
216401a344a2SDavid du Colombier 		return;
216501a344a2SDavid du Colombier 	}
216601a344a2SDavid du Colombier 	if(strcmp(arg, "clearacct") == 0) {
216701a344a2SDavid du Colombier 		memset(growacct, 0, sizeof(growacct));
216801a344a2SDavid du Colombier 		return;
216901a344a2SDavid du Colombier 	}
217001a344a2SDavid du Colombier 
217101a344a2SDavid du Colombier 	/*
217201a344a2SDavid du Colombier 	 * items depend on cw filesystem
217301a344a2SDavid du Colombier 	 */
217401a344a2SDavid du Colombier 	dev = cons.curfs->dev;
217501a344a2SDavid du Colombier 	if(dev == 0 || dev->type != Devcw || dev->private == 0) {
217601a344a2SDavid du Colombier 		print("cfs not a cw filesystem: %Z\n", dev);
217701a344a2SDavid du Colombier 		return;
217801a344a2SDavid du Colombier 	}
217901a344a2SDavid du Colombier 	cw = dev->private;
218001a344a2SDavid du Colombier 	if(strcmp(arg, "searchtag") == 0) {
218101a344a2SDavid du Colombier 		a = 0;
218201a344a2SDavid du Colombier 		if(argc > 2)
218301a344a2SDavid du Colombier 			a = number(argv[2], 0, 10);
218401a344a2SDavid du Colombier 		b = Tsuper;
218501a344a2SDavid du Colombier 		if(argc > 3)
218601a344a2SDavid du Colombier 			b = number(argv[3], 0, 10);
218701a344a2SDavid du Colombier 		n = 1000;
218801a344a2SDavid du Colombier 		if(argc > 4)
218901a344a2SDavid du Colombier 			n = number(argv[4], 0, 10);
219001a344a2SDavid du Colombier 		searchtag(dev, a, b, n);
219101a344a2SDavid du Colombier 	} else if(strcmp(arg, "mvstate") == 0) {
219201a344a2SDavid du Colombier 		if(argc < 4)
219301a344a2SDavid du Colombier 			goto bad;
219401a344a2SDavid du Colombier 		s1 = convstate(argv[2]);
219501a344a2SDavid du Colombier 		s2 = convstate(argv[3]);
219601a344a2SDavid du Colombier 		if(s1 < 0 || s2 < 0)
219701a344a2SDavid du Colombier 			goto bad;
219801a344a2SDavid du Colombier 		a = -1;
219901a344a2SDavid du Colombier 		if(argc > 4)
220001a344a2SDavid du Colombier 			a = number(argv[4], 0, 10);
220101a344a2SDavid du Colombier 		mvstates(dev, s1, s2, a);
220201a344a2SDavid du Colombier 		return;
220301a344a2SDavid du Colombier 	bad:
220401a344a2SDavid du Colombier 		print("cwcmd mvstate: bad args\n");
220501a344a2SDavid du Colombier 	} else if(strcmp(arg, "prchain") == 0) {
220601a344a2SDavid du Colombier 		a = 0;
220701a344a2SDavid du Colombier 		if(argc > 2)
220801a344a2SDavid du Colombier 			a = number(argv[2], 0, 10);
220901a344a2SDavid du Colombier 		s1 = 0;
221001a344a2SDavid du Colombier 		if(argc > 3)
221101a344a2SDavid du Colombier 			s1 = number(argv[3], 0, 10);
221201a344a2SDavid du Colombier 		prchain(dev, a, s1);
221301a344a2SDavid du Colombier 	} else if(strcmp(arg, "touchsb") == 0)
221401a344a2SDavid du Colombier 		touchsb(dev);
221501a344a2SDavid du Colombier 	else if(strcmp(arg, "savecache") == 0)
221601a344a2SDavid du Colombier 		savecache(dev);
221701a344a2SDavid du Colombier 	else if(strcmp(arg, "loadcache") == 0) {
221801a344a2SDavid du Colombier 		s1 = -1;
221901a344a2SDavid du Colombier 		if(argc > 2)
222001a344a2SDavid du Colombier 			s1 = number(argv[2], 0, 10);
222101a344a2SDavid du Colombier 		loadcache(dev, s1);
222201a344a2SDavid du Colombier 	} else if(strcmp(arg, "morecache") == 0) {
222301a344a2SDavid du Colombier 		if(argc <= 2) {
222401a344a2SDavid du Colombier 			print("arg count\n");
222501a344a2SDavid du Colombier 			return;
222601a344a2SDavid du Colombier 		}
222701a344a2SDavid du Colombier 		s1 = number(argv[2], 0, 10);
222801a344a2SDavid du Colombier 		if(argc > 3)
222901a344a2SDavid du Colombier 			s2 = number(argv[3], 0, 10);
223001a344a2SDavid du Colombier 		else
223101a344a2SDavid du Colombier 			s2 = wormsizeside(dev, s1); /* default to 1 disc side */
223201a344a2SDavid du Colombier 		morecache(dev, s1, s2);
223301a344a2SDavid du Colombier 	} else if(strcmp(arg, "blockcmp") == 0) {
223401a344a2SDavid du Colombier 		if(argc < 4) {
223501a344a2SDavid du Colombier 			print("cannot arg count\n");
223601a344a2SDavid du Colombier 			return;
223701a344a2SDavid du Colombier 		}
223801a344a2SDavid du Colombier 		s1 = number(argv[2], 0, 10);
223901a344a2SDavid du Colombier 		s2 = number(argv[3], 0, 10);
224001a344a2SDavid du Colombier 		blockcmp(dev, s1, s2);
224101a344a2SDavid du Colombier 	} else if(strcmp(arg, "startdump") == 0) {
224201a344a2SDavid du Colombier 		if(argc > 2)
224301a344a2SDavid du Colombier 			cw->nodump = number(argv[2], 0, 10);
224401a344a2SDavid du Colombier 		cw->nodump = !cw->nodump;
224501a344a2SDavid du Colombier 		if(cw->nodump)
224601a344a2SDavid du Colombier 			print("dump stopped\n");
224701a344a2SDavid du Colombier 		else
224801a344a2SDavid du Colombier 			print("dump allowed\n");
224901a344a2SDavid du Colombier 	} else if(strcmp(arg, "allflag") == 0) {
225001a344a2SDavid du Colombier 		if(argc > 2)
225101a344a2SDavid du Colombier 			cw->allflag = number(argv[2], 0, 10);
225201a344a2SDavid du Colombier 		else
225301a344a2SDavid du Colombier 			cw->allflag = !cw->allflag;
225401a344a2SDavid du Colombier 		print("allflag = %d; falsehits = %lld\n",
225501a344a2SDavid du Colombier 			cw->allflag, (Wideoff)cw->falsehits);
225601a344a2SDavid du Colombier 	} else if(strcmp(arg, "storesb") == 0) {
225701a344a2SDavid du Colombier 		a = 4168344;
225801a344a2SDavid du Colombier 		b = 0;
225901a344a2SDavid du Colombier 		if(argc > 2)
226001a344a2SDavid du Colombier 			a = number(argv[2], 4168344, 10);
226101a344a2SDavid du Colombier 		if(argc > 3)
226201a344a2SDavid du Colombier 			b = number(argv[3], 0, 10);
226301a344a2SDavid du Colombier 		storesb(dev, a, b);
226401a344a2SDavid du Colombier 	} else if(strcmp(arg, "test") == 0)
226501a344a2SDavid du Colombier 		cwtest(dev);
226601a344a2SDavid du Colombier 	else
226701a344a2SDavid du Colombier 		print("unknown cwcmd %s\n", arg);
226801a344a2SDavid du Colombier }
2269