sync with mit plan 9 version
diff --git a/src/cmd/venti/devnull.c b/src/cmd/venti/devnull.c
index a8ab628..fdad553 100644
--- a/src/cmd/venti/devnull.c
+++ b/src/cmd/venti/devnull.c
@@ -30,7 +30,6 @@
 	VtReq *r;
 	VtSrv *srv;
 	char *address;
-	Packet *p;
 
 	fmtinstall('V', vtscorefmt);
 	fmtinstall('F', vtfcallfmt);
@@ -50,7 +49,7 @@
 
 	srv = vtlisten(address);
 	if(srv == nil)
-		sysfatal("vtlisten %s: %s", address);
+		sysfatal("vtlisten %s: %r", address);
 
 	while((r = vtgetreq(srv)) != nil){
 		r->rx.msgtype = r->tx.msgtype+1;
diff --git a/src/cmd/venti/mkfile b/src/cmd/venti/mkfile
index ca178d9..eb68bab 100644
--- a/src/cmd/venti/mkfile
+++ b/src/cmd/venti/mkfile
@@ -13,3 +13,6 @@
 <$PLAN9/src/mkmany
 <$PLAN9/src/mkdirs
 
+
+extra:V: $O.devnull $O.mkroot $O.randtest $O.readlist $O.ro $O.root
+
diff --git a/src/cmd/venti/mkroot.c b/src/cmd/venti/mkroot.c
index f18cbf3..8c38b1d 100644
--- a/src/cmd/venti/mkroot.c
+++ b/src/cmd/venti/mkroot.c
@@ -1,6 +1,7 @@
-#include "stdinc.h"
-#include "dat.h"
-#include "fns.h"
+#include <u.h>
+#include <libc.h>
+#include <venti.h>
+#include <thread.h>
 
 char *host;
 
@@ -31,14 +32,15 @@
 	if(argc != 5)
 		usage();
 
-	ventifmtinstall();
+	fmtinstall('V', vtscorefmt);
+	fmtinstall('F', vtfcallfmt);
 
 	strecpy(root.name, root.name+sizeof root.name, argv[0]);
 	strecpy(root.type, root.type+sizeof root.type, argv[1]);
-	if(vtparsescore(argv[2], strlen(argv[2]), nil, root.score) < 0)
+	if(vtparsescore(argv[2], nil, root.score) < 0)
 		sysfatal("bad score '%s'", argv[2]);
 	root.blocksize = atoi(argv[3]);
-	if(vtparsescore(argv[4], strlen(argv[4]), nil, root.prev) < 0)
+	if(vtparsescore(argv[4], nil, root.prev) < 0)
 		sysfatal("bad score '%s'", argv[4]);
 	vtrootpack(&root, buf);
 
diff --git a/src/cmd/venti/randtest.c b/src/cmd/venti/randtest.c
index b7a09ef..2a1fa6e 100644
--- a/src/cmd/venti/randtest.c
+++ b/src/cmd/venti/randtest.c
@@ -35,6 +35,7 @@
 	uchar score[VtScoreSize], score2[VtScoreSize];
 	DigestState ds;
 
+	USED(buf2);
 	memset(&ds, 0, sizeof ds);
 	if(doublecheck)
 		sha1((uchar*)buf, blocksize, score, &ds);
diff --git a/src/cmd/venti/srv/bloom.c b/src/cmd/venti/srv/bloom.c
index 7ea5f64..04fd651 100644
--- a/src/cmd/venti/srv/bloom.c
+++ b/src/cmd/venti/srv/bloom.c
@@ -27,7 +27,7 @@
 			return -1;
 	
 fprint(2, "bloom size %lud nhash %d\n", b->size, b->nhash);
-	b->mask = b->size-1;
+	b->bitmask = (b->size<<3) - 1;
 	b->data = data;
 	return 0;
 }
@@ -47,11 +47,17 @@
 	b = vtmallocz(sizeof *b);
 	if(readpart(p, 0, buf, sizeof buf) < 0)
 		return nil;
+	/*
+	 * pass buf as b->data so that bloominit
+	 * can parse header.  won't be used for
+	 * accessing bits (cleared below).
+	 */
 	if(bloominit(b, 0, buf) < 0){
 		vtfree(b);
 		return nil;
 	}
 	b->part = p;
+	b->data = nil;
 	return b;
 }
 
@@ -61,7 +67,6 @@
 	uchar *data;
 	
 	data = vtmallocz(b->size);
-fprint(2, "bloom data %lud\n", b->size);
 	b->data = data;
 	if(b->size == MaxBloomSize)	/* 2^32 overflows ulong */
 		addstat(StatBloomBits, b->size*8-1);
@@ -145,7 +150,7 @@
 	tab = (u32int*)b->data;
 	for(i=0; i<b->nhash; i++){
 		x = h[i];
-		y = &tab[(x&b->mask)>>5];
+		y = &tab[(x&b->bitmask)>>5];
 		z = 1<<(x&31);
 		if(!(*y&z)){
 			nnew++;
@@ -169,7 +174,7 @@
 	tab = (u32int*)b->data;
 	for(i=0; i<b->nhash; i++){
 		x = h[i];
-		if(!(tab[(x&b->mask)>>5] & (1<<(x&31))))
+		if(!(tab[(x&b->bitmask)>>5] & (1<<(x&31))))
 			return 0;
 	}
 	return 1;
diff --git a/src/cmd/venti/srv/checkarenas.c b/src/cmd/venti/srv/checkarenas.c
index 3b7202e..ea52712 100644
--- a/src/cmd/venti/srv/checkarenas.c
+++ b/src/cmd/venti/srv/checkarenas.c
@@ -112,7 +112,7 @@
 	argc--;
 	argv++;
 
-	part = initpart(file, ORDWR|ODIRECT);
+	part = initpart(file, (fix ? ORDWR : OREAD)|ODIRECT);
 	if(part == nil)
 		sysfatal("can't open partition %s: %r", file);
 
diff --git a/src/cmd/venti/srv/checkindex.c b/src/cmd/venti/srv/checkindex.c
index 7639b2c..ef0e4ec 100644
--- a/src/cmd/venti/srv/checkindex.c
+++ b/src/cmd/venti/srv/checkindex.c
@@ -116,8 +116,7 @@
 	if(b == nil || z == nil || ies == nil){
 		werrstr("allocating: %r");
 		ok = -1;
-		goto breakout;
-		return -1;
+		goto out;
 	}
 	ok = 0;
 	next = 0;
@@ -138,7 +137,7 @@
 					}
 					if(ok < 0)
 						werrstr("%d spurious entries, %d missing, %d wrong", extra, missing, wrong);
-					goto breakout;
+					goto out;
 				}
 				bok = checkbucket(ix, next, &zib);
 				if(bok < 0)
@@ -150,14 +149,14 @@
 				break;
 			werrstr("internal error: bucket out of range");
 			ok = -1;
-			goto breakout;
+			goto out;
 		}
 		bok = checkbucket(ix, buck, &ib);
 		if(bok < 0)
 			ok = -1;
 		next = buck + 1;
 	}
-breakout:
+out:
 	freeiestream(ies);
 	freezblock(z);
 	freezblock(b);
diff --git a/src/cmd/venti/srv/cmparenas.c b/src/cmd/venti/srv/cmparenas.c
index 317b020..322f16e 100644
--- a/src/cmd/venti/srv/cmparenas.c
+++ b/src/cmd/venti/srv/cmparenas.c
@@ -51,21 +51,64 @@
 	return 0;
 }
 
+static int
+printheader(char *name, ArenaHead *head, int fd)
+{
+	Arena arena;
+	vlong baseoff, lo, hi, off;
+	int clumpmax;
+	
+	off = seek(fd, 0, 1);
+	seek(fd, off + head->size - head->blocksize, 0);
+	if(readblock(fd, data, head->blocksize) < 0){
+		fprint(2, "%s: reading arena tail: %r\n", name);
+		return -1;
+	}
+	seek(fd, off, 0);
+
+	memset(&arena, 0, sizeof arena);
+	if(unpackarena(&arena, data) < 0){
+		fprint(2, "%s: unpack arena tail: %r\n", name);
+		return -1;
+	}
+	arena.blocksize = head->blocksize;
+	arena.base = off + head->blocksize;
+	arena.clumpmax = arena.blocksize / ClumpInfoSize;
+	arena.size = head->size - 2*head->blocksize;
+
+	fprint(2, "%s: base=%llx size=%llx blocksize=%x\n", name, off, head->size, head->blocksize);
+
+	baseoff = head->blocksize;
+	fprint(2, "\t%llx-%llx: head\n", (vlong)0, baseoff);
+	lo = baseoff;
+	hi = baseoff + arena.diskstats.used;
+	fprint(2, "\t%llx-%llx: data (%llx)\n", lo, hi, hi - lo);
+	hi = head->size - head->blocksize;
+	clumpmax = head->blocksize / ClumpInfoSize;
+	if(clumpmax > 0)
+		lo = hi - (u64int)arena.diskstats.clumps/clumpmax * head->blocksize;
+	else
+		lo = hi;
+	fprint(2, "\t%llx-%llx: clumps (%llx)\n", lo, hi, hi - lo);
+	fprint(2, "\t%llx-%llx: tail\n", hi, hi + head->blocksize);
+	
+	fprint(2, "arena:\n");
+	printarena(2, &arena);
+	return 0;
+}
+
 static void
 cmparena(char *name, vlong len)
 {
-	Arena arena;
 	ArenaHead head;
 	DigestState s;
 	u64int n, e;
 	u32int bs;
-	u8int score[VtScoreSize];
 	int i, j;
 	char buf[20];
 
 	fprint(2, "cmp %s\n", name);
 
-	memset(&arena, 0, sizeof arena);
 	memset(&s, 0, sizeof s);
 
 	/*
@@ -104,6 +147,9 @@
 	seek(fd, -HeadSize, 1);
 	seek(fd1, -HeadSize, 1);
 
+	if(printheader(name, &head, fd) < 0)
+		return;
+	
 	/*
 	 * now we know how much to read
 	 * read everything but the last block, which is special
diff --git a/src/cmd/venti/srv/conv.c b/src/cmd/venti/srv/conv.c
index 58b3d25..6c8d9ef 100644
--- a/src/cmd/venti/srv/conv.c
+++ b/src/cmd/venti/srv/conv.c
@@ -34,7 +34,7 @@
 	for(i=0; i<nelem(magics); i++)
 		if(magics[i].m == m)
 			return magics[i].s;
-	sprint(s, "0x%08ux", m);
+	sprint(s, "%#08ux", m);
 	return s;
 }
 
@@ -61,7 +61,7 @@
 
 	m = U32GET(p);
 	if(m != ArenaPartMagic){
-		seterr(ECorrupt, "arena set has wrong magic number: %s expected ArenaPartMagic (%lux)", fmtmagic(fbuf, m), ArenaPartMagic);
+		seterr(ECorrupt, "arena set has wrong magic number: %s expected ArenaPartMagic (%#lux)", fmtmagic(fbuf, m), ArenaPartMagic);
 		return -1;
 	}
 	p += U32Size;
@@ -112,7 +112,7 @@
 
 	m = U32GET(p);
 	if(m != ArenaMagic){
-		seterr(ECorrupt, "arena has wrong magic number: %s expected ArenaMagic (%lux)", fmtmagic(fbuf, m), ArenaMagic);
+		seterr(ECorrupt, "arena has wrong magic number: %s expected ArenaMagic (%#lux)", fmtmagic(fbuf, m), ArenaMagic);
 		return -1;
 	}
 	p += U32Size;
@@ -276,10 +276,15 @@
 	u8int *p;
 	u32int m;
 	int sz;
+	char fbuf[20];
 
 	p = buf;
 
 	m = U32GET(p);
+	if(m != ArenaHeadMagic){
+		seterr(ECorrupt, "arena has wrong magic number: %s expected ArenaHeadMagic (%#lux)", fmtmagic(fbuf, m), ArenaHeadMagic);
+		return -1;
+	}
 	/* XXX check magic! */
 
 	p += U32Size;
@@ -497,7 +502,7 @@
 
 	m = U32GET(p);
 	if(m != ISectMagic){
-		seterr(ECorrupt, "index section has wrong magic number: %s expected ISectMagic (%lux)",
+		seterr(ECorrupt, "index section has wrong magic number: %s expected ISectMagic (%#lux)",
 			fmtmagic(fbuf, m), ISectMagic);
 		return -1;
 	}
@@ -665,7 +670,7 @@
 
 	m = U32GET(p);
 	if(m != BloomMagic){
-		seterr(ECorrupt, "bloom filter has wrong magic number: %s expected BloomMagic (%lux)", fmtmagic(fbuf, m), (ulong)BloomMagic);
+		seterr(ECorrupt, "bloom filter has wrong magic number: %s expected BloomMagic (%#lux)", fmtmagic(fbuf, m), (ulong)BloomMagic);
 		return -1;
 	}
 	p += U32Size;
@@ -682,6 +687,10 @@
 
 	b->size = U32GET(p);
 	p += U32Size;
+	if(b->size < BloomHeadSize || b->size > MaxBloomSize || (b->size&(b->size-1))){
+		seterr(ECorrupt, "bloom filter has invalid size %#lux", b->size);
+		return -1;
+	}
 
 	if(buf + BloomHeadSize != p)
 		sysfatal("unpackarena unpacked wrong amount");
diff --git a/src/cmd/venti/srv/dat.h b/src/cmd/venti/srv/dat.h
index 4801204..ede2779 100644
--- a/src/cmd/venti/srv/dat.h
+++ b/src/cmd/venti/srv/dat.h
@@ -696,7 +696,7 @@
 	QLock mod;		/* one marker at a time, protects nb */
 	int nhash;
 	ulong size;		/* bytes in tab */
-	ulong mask;		/* to produce index */
+	ulong bitmask;		/* to produce bit index */
 	u8int *data;
 	Part *part;
 	Channel *writechan;
diff --git a/src/cmd/venti/srv/dcache.c b/src/cmd/venti/srv/dcache.c
index 4d6d086..4f87e77 100644
--- a/src/cmd/venti/srv/dcache.c
+++ b/src/cmd/venti/srv/dcache.c
@@ -169,11 +169,24 @@
 		b = _getdblock(ra.part, ra.addr, OREAD, 2);
 		putdblock(b);
 	}
-}	
+}
 
+/*
+ * We do readahead a whole arena at a time now,
+ * so dreadahead is a no-op.  The original implementation
+ * is in unused_dreadahead below.
+ */
 void
 dreadahead(Part *part, u64int addr, int miss)
 {
+	USED(part);
+	USED(addr);
+	USED(miss);
+}
+
+void
+unused_dreadahead(Part *part, u64int addr, int miss)
+{
 	Ra ra;
 	static struct {
 		Part *part;
@@ -185,7 +198,6 @@
 		int dir;
 	} lastra;
 
-return;
 	if(miss){
 		if(lastmiss.part==part && lastmiss.addr==addr-dcache.size){
 		XRa:
diff --git a/src/cmd/venti/srv/fixarenas.c b/src/cmd/venti/srv/fixarenas.c
index 9551594..f93bba7 100644
--- a/src/cmd/venti/srv/fixarenas.c
+++ b/src/cmd/venti/srv/fixarenas.c
@@ -976,7 +976,6 @@
 		else
 			p = &cibuf[*p].left;
 	}
-	return nil; 	/* stupid 8c */
 }
 
 void
@@ -1024,7 +1023,6 @@
 		else
 			p = cibuf[p].left;
 	}
-	return 0;	/* stupid 8c */
 }
 
 int
diff --git a/src/cmd/venti/srv/fns.h b/src/cmd/venti/srv/fns.h
index 1a6f1e4..c631bfd 100644
--- a/src/cmd/venti/srv/fns.h
+++ b/src/cmd/venti/srv/fns.h
@@ -51,6 +51,13 @@
 DBlock		*_getdblock(Part *part, u64int addr, int mode, int load);
 DBlock		*getdblock(Part *part, u64int addr, int mode);
 u32int		hashbits(u8int *score, int nbits);
+char		*hargstr(HConnect*, char*, char*);
+vlong	hargint(HConnect*, char*, vlong);
+int		hdebug(HConnect*);
+int		hdisk(HConnect*);
+int		hnotfound(HConnect*);
+int		hsethtml(HConnect*);
+int		hsettext(HConnect*);
 int		httpdinit(char *address, char *webroot);
 int		iaddrcmp(IAddr *ia1, IAddr *ia2);
 IEntry*	icachedirty(u32int, u32int, u64int);
@@ -89,6 +96,7 @@
 int		loadientry(Index *index, u8int *score, int type, IEntry *ie);
 void		logerr(int severity, char *fmt, ...);
 Lump		*lookuplump(u8int *score, int type);
+int		_lookupscore(u8int *score, int type, IAddr *ia, int *rac);
 int		lookupscore(u8int *score, int type, IAddr *ia, int *rac);
 int		maparenas(AMap *am, Arena **arenas, int n, char *what);
 void		markbloomfilter(Bloom*, u8int*);
diff --git a/src/cmd/venti/srv/graph.c b/src/cmd/venti/srv/graph.c
index 7a1ca2c..cbad1ad 100644
--- a/src/cmd/venti/srv/graph.c
+++ b/src/cmd/venti/srv/graph.c
@@ -111,7 +111,7 @@
 Memimage*
 statgraph(Graph *g)
 {
-	int i, lastlo, nbin, x, lo, hi, min, max, first;
+	int i, nbin, x, lo, hi, min, max, first;
 	Memimage *m;
 	Rectangle r;
 	Statbin *b, bin[2000];	/* 32 kB, but whack is worse */
@@ -178,7 +178,6 @@
 		drawlabel(m, Pt(r.min.x, r.max.y-smallfont->height), min);
 	
 	/* actual data */
-	lastlo = -1;
 	for(i=0; i<nbin; i++){
 		b = &bin[i];
 		if(b->nsamp == 0)
@@ -187,16 +186,8 @@
 		hi = scalept(b->max, min, max, r.max.y, r.min.y);
 		x = r.min.x+i;
 		hi-=2;
-		if(0)
-		if(lastlo != -1){
-			if(lastlo < lo)
-				memimagedraw(m, Rect(x-1, lastlo, x, lo), hifill[g->fill%nelem(hifill)], ZP, memopaque, ZP, S);
-			else if(lastlo > lo)
-				memimagedraw(m, Rect(x-1, lo, x, lastlo), hifill[g->fill%nelem(hifill)], ZP, memopaque, ZP, S);
-		}
 		memimagedraw(m, Rect(x, hi, x+1,lo), hifill[g->fill%nelem(hifill)], ZP, memopaque, ZP, S);
 		memimagedraw(m, Rect(x, lo, x+1, r.max.y), lofill[g->fill%nelem(lofill)], ZP, memopaque, ZP, S);
-		lastlo = lo;
 	}
 
 	if(bin[nbin-1].nsamp)
diff --git a/src/cmd/venti/srv/httpd.c b/src/cmd/venti/srv/httpd.c
index 04d19d9..e71bd43 100644
--- a/src/cmd/venti/srv/httpd.c
+++ b/src/cmd/venti/srv/httpd.c
@@ -36,7 +36,6 @@
 static	int		hdcachekick(HConnect *c);
 static	int		hicacheflush(HConnect *c);
 static	int		hdcacheflush(HConnect *c);
-static	int		notfound(HConnect *c);
 static	int		httpdobj(char *name, int (*f)(HConnect*));
 static	int		xgraph(HConnect *c);
 static	int		xset(HConnect *c);
@@ -61,15 +60,15 @@
 	httpdobj("/flushdcache", hdcacheflush);
 	httpdobj("/kickicache", hicachekick);
 	httpdobj("/kickdcache", hdcachekick);
-	httpdobj("/graph/", xgraph);
+	httpdobj("/graph", xgraph);
 	httpdobj("/set", xset);
-	httpdobj("/set/", xset);
 	httpdobj("/log", xlog);
-	httpdobj("/log/", xlog);
 	httpdobj("/empty", hempty);
 	httpdobj("/emptyicache", hicacheempty);
 	httpdobj("/emptylumpcache", hlcacheempty);
 	httpdobj("/emptydcache", hdcacheempty);
+	httpdobj("/disk", hdisk);
+	httpdobj("/debug", hdebug);
 
 	if(vtproc(listenproc, address) < 0)
 		return -1;
@@ -168,6 +167,11 @@
 		 */
 		if(hparsereq(c, 0) < 0)
 			break;
+		
+		if(c->req.search)
+			c->req.searchpairs = hparsequery(c, c->req.search);
+		else
+			c->req.searchpairs = nil;
 
 		for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
 			n = strlen(objs[i].name);
@@ -179,6 +183,7 @@
 		}
 		ok = fromwebdir(c);
 	found:
+		hflush(&c->hout);
 		if(c->head.closeit)
 			ok = -1;
 		hreqcleanup(c);
@@ -191,6 +196,27 @@
 	free(c);
 }
 
+char*
+hargstr(HConnect *c, char *name, char *def)
+{
+	HSPairs *p;
+	
+	for(p=c->req.searchpairs; p; p=p->next)
+		if(strcmp(p->s, name) == 0)
+			return p->t;
+	return def;
+}
+
+vlong
+hargint(HConnect *c, char *name, vlong def)
+{
+	char *a;
+	
+	if((a = hargstr(c, name, nil)) == nil)
+		return def;
+	return atoll(a);
+}
+
 static int
 percent(ulong v, ulong total)
 {
@@ -217,8 +243,8 @@
 	return 0;
 }
 
-static int
-preqtype(HConnect *c, char *type)
+int
+hsettype(HConnect *c, char *type)
 {
 	Hio *hout;
 	int r;
@@ -243,10 +269,16 @@
 	return 0;
 }
 
-static int
-preqtext(HConnect *c)
+int
+hsethtml(HConnect *c)
 {
-	return preqtype(c, "text/plain");
+	return hsettype(c, "text/html; charset=utf-8");
+}
+
+int
+hsettext(HConnect *c)
+{
+	return hsettype(c, "text/plain; charset=utf-8");
 }
 
 static int
@@ -274,8 +306,8 @@
 	return hflush(hout);
 }
 	
-static int
-notfound(HConnect *c)
+int
+hnotfound(HConnect *c)
 {
 	int r;
 
@@ -305,16 +337,16 @@
 	Dir *d;
 	
 	if(webroot == nil || strstr(c->req.uri, ".."))
-		return notfound(c);
+		return hnotfound(c);
 	snprint(buf, sizeof buf-20, "%s/%s", webroot, c->req.uri+1);
 	defaulted = 0;
 reopen:
 	if((fd = open(buf, OREAD)) < 0)
-		return notfound(c);
+		return hnotfound(c);
 	d = dirfstat(fd);
 	if(d == nil){
 		close(fd);
-		return notfound(c);
+		return hnotfound(c);
 	}
 	if(d->mode&DMDIR){
 		if(!defaulted){
@@ -325,7 +357,7 @@
 			goto reopen;
 		}
 		free(d);
-		return notfound(c);
+		return hnotfound(c);
 	}
 	free(d);
 	p = buf+strlen(buf);
@@ -337,7 +369,7 @@
 			break;
 		}
 	}
-	if(preqtype(c, type) < 0){
+	if(hsettype(c, type) < 0){
 		close(fd);
 		return 0;
 	}
@@ -372,54 +404,41 @@
 };
 
 static int
-xsetlist(HConnect *c)
-{
-	int i;
-	
-	if(preqtype(c, "text/plain") < 0)
-		return -1;
-	for(i=0; namedints[i].name; i++)
-		print("%s = %d\n", namedints[i].name, *namedints[i].p);
-	hflush(&c->hout);
-	return 0;
-}
-
-
-
-static int
 xset(HConnect *c)
 {
-	int i, nf, r;
-	char *f[10], *s;
+	int i, old;
+	char *name, *value;
 
-	if(strcmp(c->req.uri, "/set") == 0 || strcmp(c->req.uri, "/set/") == 0)
-		return xsetlist(c);
+	if(hsettext(c) < 0)
+		return -1;
 
-	s = estrdup(c->req.uri);
-	nf = getfields(s+strlen("/set/"), f, nelem(f), 1, "/");
-
-	if(nf < 1){
-		r = preqtext(c);
-		if(r < 0)
-			return r;
+	if((name = hargstr(c, "name", nil)) == nil || name[0] == 0){
 		for(i=0; namedints[i].name; i++)
 			hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
 		hflush(&c->hout);
 		return 0;
 	}
-	for(i=0; namedints[i].name; i++){
-		if(strcmp(f[0], namedints[i].name) == 0){
-			if(nf >= 2)
-				*namedints[i].p = atoi(f[1]);
-			r = preqtext(c);
-			if(r < 0)
-				return r;
-			hprint(&c->hout, "%s = %d\n", f[0], *namedints[i].p);
-			hflush(&c->hout);
-			return 0;
-		}
+
+	for(i=0; namedints[i].name; i++)
+		if(strcmp(name, namedints[i].name) == 0)
+			break;
+	if(!namedints[i].name){
+		hprint(&c->hout, "%s not found\n", name);
+		hflush(&c->hout);
+		return 0;
 	}
-	return notfound(c);
+
+	if((value = hargstr(c, "value", nil)) == nil || value[0] == 0){
+		hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
+		hflush(&c->hout);
+		return 0;
+	}
+	
+	old = *namedints[i].p;
+	*namedints[i].p = atoll(value);
+	hprint(&c->hout, "%s = %d (was %d)\n", name, *namedints[i].p, old);
+	hflush(&c->hout);
+	return 0;
 }
 
 static int
@@ -428,7 +447,7 @@
 	Hio *hout;
 	int r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 
@@ -503,7 +522,7 @@
 	vlong clumps, cclumps, uncsize, used, size;
 	int i, r, active;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -567,7 +586,7 @@
 	Hio *hout;
 	int r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -586,7 +605,7 @@
 	Hio *hout;
 	int r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -603,7 +622,7 @@
 	Hio *hout;
 	int r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -620,7 +639,7 @@
 	Hio *hout;
 	int r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -636,7 +655,7 @@
 	Hio *hout;
 	int r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -653,7 +672,7 @@
 	Hio *hout;
 	int r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -669,7 +688,7 @@
 	Hio *hout;
 	int r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -686,7 +705,7 @@
 	Hio *hout;
 	int r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -704,7 +723,7 @@
 	Index *ix;
 	int i, r;
 
-	r = preqtext(c);
+	r = hsettext(c);
 	if(r < 0)
 		return r;
 	hout = &c->hout;
@@ -772,6 +791,23 @@
 }
 
 static long
+div(long a, long b)
+{
+	if(b == 0)
+		b++;
+	return a/b;
+}
+
+static long
+divdiffgraph(Stats *s, Stats *t, void *va)
+{
+	Arg *a;
+
+	a = va;
+	return div(t->n[a->index] - s->n[a->index], t->n[a->index2] - s->n[a->index2]);
+}
+
+static long
 netbw(Stats *s)
 {
 	ulong *n;
@@ -928,79 +964,59 @@
 static int
 xgraph(HConnect *c)
 {
-	char *f[20], *s;
+	char *name;
 	Hio *hout;
 	Memimage *m;
-	int i, nf, dotext;
+	int dotext;
 	Graph g;
 	Arg arg;
+	char *graph, *a;
 
-	s = estrdup(c->req.uri);
-if(0) fprint(2, "graph %s\n" ,s);
-	memset(&g, 0, sizeof g);
-	nf = getfields(s+strlen("/graph/"), f, nelem(f), 1, "/");
-	if(nf < 1){
-		werrstr("bad syntax -- not enough fields");
+	name = hargstr(c, "arg", "");
+	if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){
+		werrstr("unknown name %s", name);
 		goto error;
 	}
-	if((arg.index = findname(f[0])) == -1 && strcmp(f[0], "*") != 0){
-		werrstr("unknown name %s", f[0]);
+	a = hargstr(c, "arg2", "");
+	if(a[0] && (arg.index2 = findname(a)) == -1){
+		werrstr("unknown name %s", a);
 		goto error;
 	}
+
 	g.arg = &arg;
-	g.t0 = -120;
-	g.t1 = 0;
-	g.min = -1;
-	g.max = -1;
-	g.fn = rawgraph;
-	g.wid = -1;
-	g.ht = -1;
-	dotext = 0;
-	g.fill = -1;
-	for(i=1; i<nf; i++){
-		if(strncmp(f[i], "t0=", 3) == 0)
-			g.t0 = atoi(f[i]+3);
-		else if(strncmp(f[i], "t1=", 3) == 0)
-			g.t1 = atoi(f[i]+3);
-		else if(strncmp(f[i], "min=", 4) == 0)
-			g.min = atoi(f[i]+4);
-		else if(strncmp(f[i], "max=", 4) == 0)
-			g.max = atoi(f[i]+4);
-		else if(strncmp(f[i], "pct=", 4) == 0){
-			if((arg.index2 = findname(f[i]+4)) == -1){
-				werrstr("unknown name %s", f[i]+4);
-				goto error;
-			}
-			g.fn = pctgraph;
-			g.min = 0;
-			g.max = 100;
-		}else if(strncmp(f[i], "pctdiff=", 8) == 0){
-			if((arg.index2 = findname(f[i]+8)) == -1){
-				werrstr("unknown name %s", f[i]+8);
-				goto error;
-			}
-			g.fn = pctdiffgraph;
-			g.min = 0;
-			g.max = 100;
-		}else if(strcmp(f[i], "diff") == 0)
-			g.fn = diffgraph;
-		else if(strcmp(f[i], "text") == 0)
-			dotext = 1;
-		else if(strncmp(f[i], "wid=", 4) == 0)
-			g.wid = atoi(f[i]+4);
-		else if(strncmp(f[i], "ht=", 3) == 0)
-			g.ht = atoi(f[i]+3);
-		else if(strncmp(f[i], "fill=", 5) == 0)
-			g.fill = atoi(f[i]+5);
-		else if(strcmp(f[i], "diskbw") == 0)
-			g.fn = diskgraph;
-		else if(strcmp(f[i], "iobw") == 0)
-			g.fn = iograph;
-		else if(strcmp(f[i], "netbw") == 0)
-			g.fn = netgraph;
+	g.t0 = hargint(c, "t0", -120);
+	g.t1 = hargint(c, "t1", 0);
+	g.min = hargint(c, "min", -1);
+	g.max = hargint(c, "max", -1);
+	g.wid = hargint(c, "wid", -1);
+	g.ht = hargint(c, "ht", -1);
+	dotext = hargstr(c, "text", "")[0] != 0;
+	g.fill = hargint(c, "fill", -1);
+	
+	graph = hargstr(c, "graph", "raw");
+	if(strcmp(graph, "raw") == 0)
+		g.fn = rawgraph;
+	else if(strcmp(graph, "diskbw") == 0)
+		g.fn = diskgraph;
+	else if(strcmp(graph, "iobw") == 0)
+		g.fn = iograph;
+	else if(strcmp(graph, "netbw") == 0)
+		g.fn = netgraph;
+	else if(strcmp(graph, "diff") == 0)
+		g.fn = diffgraph;
+	else if(strcmp(graph, "pct") == 0)
+		g.fn = pctgraph;
+	else if(strcmp(graph, "pctdiff") == 0)
+		g.fn = pctdiffgraph;
+	else if(strcmp(graph, "divdiff") == 0)
+		g.fn = divdiffgraph;
+	else{
+		werrstr("unknown graph %s", graph);
+		goto error;
 	}
+
 	if(dotext){
-		preqtype(c, "text/plain");
+		hsettype(c, "text/plain");
 		dotextbin(&c->hout, &g);
 		hflush(&c->hout);
 		return 0;
@@ -1010,7 +1026,7 @@
 	if(m == nil)
 		goto error;
 
-	if(preqtype(c, "image/png") < 0)
+	if(hsettype(c, "image/png") < 0)
 		return -1;
 	hout = &c->hout;
 	writepng(hout, m);
@@ -1018,18 +1034,16 @@
 	freememimage(m);
 	qunlock(&memdrawlock);
 	hflush(hout);
-	free(s);
 	return 0;
 
 error:
-	free(s);
 	return herror(c);
 }
 
 static int
 xloglist(HConnect *c)
 {
-	if(preqtype(c, "text/html") < 0)
+	if(hsettype(c, "text/html") < 0)
 		return -1;
 	vtloghlist(&c->hout);
 	hflush(&c->hout);
@@ -1042,15 +1056,13 @@
 	char *name;
 	VtLog *l;
 
-	if(strcmp(c->req.uri, "/log") == 0 || strcmp(c->req.uri, "/log/") == 0)
+	name = hargstr(c, "log", "");
+	if(!name[0])
 		return xloglist(c);
-	if(strncmp(c->req.uri, "/log/", 5) != 0)
-		return notfound(c);
-	name = c->req.uri + strlen("/log/");
 	l = vtlogopen(name, 0);
 	if(l == nil)
-		return notfound(c);
-	if(preqtype(c, "text/html") < 0){
+		return hnotfound(c);
+	if(hsettype(c, "text/html") < 0){
 		vtlogclose(l);
 		return -1;
 	}
@@ -1063,7 +1075,7 @@
 static int
 xindex(HConnect *c)
 {
-	if(preqtype(c, "text/xml") < 0)
+	if(hsettype(c, "text/xml") < 0)
 		return -1;
 	xmlindex(&c->hout, mainindex, "index", 0);
 	hflush(&c->hout);
@@ -1158,7 +1170,7 @@
 	p = vtlognames(&n);
 	qsort(p, n, sizeof(p[0]), strpcmp);
 	for(i=0; i<n; i++)
-		hprint(h, "<a href=\"/log/%s\">%s</a><br>\n", p[i], p[i]);
+		hprint(h, "<a href=\"/log?log=%s\">%s</a><br>\n", p[i], p[i]);
 	vtfree(p);
 	hprint(h, "</body></html>\n");
 }
diff --git a/src/cmd/venti/srv/icache.c b/src/cmd/venti/srv/icache.c
index 49f741e..56513aa 100644
--- a/src/cmd/venti/srv/icache.c
+++ b/src/cmd/venti/srv/icache.c
@@ -86,6 +86,42 @@
 	}
 }
 
+int
+_lookupscore(u8int *score, int type, IAddr *ia, int *rac)
+{
+	u32int h;
+	IEntry *ie, *last;
+
+	qlock(&icache.lock);
+	h = hashbits(score, icache.bits);
+	last = nil;
+	for(ie = icache.heads[h]; ie != nil; ie = ie->next){
+		if((ie->ia.type == type || type == -1) && scorecmp(ie->score, score)==0){
+			if(last != nil)
+				last->next = ie->next;
+			else
+				icache.heads[h] = ie->next;
+			addstat(StatIcacheHit, 1);
+			if(rac)
+				ie->rac = 1;
+			trace(TraceLump, "lookupscore incache");
+			ie->next = icache.heads[h];
+			icache.heads[h] = ie;
+
+			*ia = ie->ia;
+			if(rac)
+				*rac = ie->rac;
+			qunlock(&icache.lock);
+			return 0;
+		}
+		last = ie;
+	}
+	addstat(StatIcacheMiss, 1);
+	qunlock(&icache.lock);
+	return -1;
+}
+
+
 /*
 ZZZ need to think about evicting the correct IEntry,
 and writing back the wtime.
@@ -97,88 +133,72 @@
 int
 lookupscore(u8int *score, int type, IAddr *ia, int *rac)
 {
-	IEntry d, *ie, *last;
+	IEntry d, *ie;
 	u32int h;
 	u64int aa;
 	Arena *load;
-	int i;
+	int i, ret;
 	uint ms;
 
-	load = nil;
 	aa = 0;
 	ms = msec();
 	
 	trace(TraceLump, "lookupscore %V.%d", score, type);
 
-	qlock(&icache.lock);
-	h = hashbits(score, icache.bits);
-	last = nil;
-	for(ie = icache.heads[h]; ie != nil; ie = ie->next){
-		if(ie->ia.type == type && scorecmp(ie->score, score)==0){
-			if(last != nil)
-				last->next = ie->next;
-			else
-				icache.heads[h] = ie->next;
-			addstat(StatIcacheHit, 1);
-			ie->rac = 1;
-			trace(TraceLump, "lookupscore incache");
-			goto found;
+	ret = 0;
+	if(_lookupscore(score, type, ia, rac) < 0){
+		if(loadientry(mainindex, score, type, &d) < 0){
+			ret = -1;
+			goto out;
 		}
-		last = ie;
-	}
-	addstat(StatIcacheMiss, 1);
-	qunlock(&icache.lock);
 
-	if(loadientry(mainindex, score, type, &d) < 0){
-		ms = msec() - ms;
-		addstat2(StatIcacheRead, 1, StatIcacheReadTime, ms);
-		return -1;
-	}
+		/* failed in cache but found on disk - fill cache. */
+		trace(TraceLump, "lookupscore loaded");
+		addstat(StatIcacheFill, 1);
 
-	addstat(StatIcacheFill, 1);
-
-	trace(TraceLump, "lookupscore loaded");
-
-	/*
-	 * no one else can load an entry for this score,
-	 * since we have the overall score lock.
-	 */
-	qlock(&icache.lock);
-
-	/*
-	 * If we notice that all the hits are coming from one arena,
-	 * load the table of contents for that arena into the cache.
-	 */
-	ie = icachealloc(&d.ia, score);
-	if(icacheprefetch){
-		icache.last[icache.nlast++%nelem(icache.last)] = amapitoa(mainindex, ie->ia.addr, &aa);
-		aa = ie->ia.addr - aa;	/* compute base addr of arena */
-		for(i=0; i<nelem(icache.last); i++)
-			if(icache.last[i] != icache.last[0])
-				break;
-		if(i==nelem(icache.last) && icache.lastload != icache.last[0]){
-			load = icache.last[0];
-			icache.lastload = load;
+		/*
+		 * no one else can load an entry for this score,
+		 * since we have this score's lump's lock.
+		 */
+		qlock(&icache.lock);
+	
+		/*
+		 * If we notice that all the hits are coming from one arena,
+		 * load the table of contents for that arena into the cache.
+		 */
+		load = nil;
+		h = hashbits(score, icache.bits);
+		ie = icachealloc(&d.ia, score);
+		if(icacheprefetch){
+			icache.last[icache.nlast++%nelem(icache.last)] = amapitoa(mainindex, ie->ia.addr, &aa);
+			aa = ie->ia.addr - aa;	/* compute base addr of arena */
+			for(i=0; i<nelem(icache.last); i++)
+				if(icache.last[i] != icache.last[0])
+					break;
+			if(i==nelem(icache.last) && icache.lastload != icache.last[0]){
+				load = icache.last[0];
+				icache.lastload = load;
+			}
+		}
+	
+		ie->next = icache.heads[h];
+		icache.heads[h] = ie;
+	
+		*ia = ie->ia;
+		*rac = ie->rac;
+	
+		qunlock(&icache.lock);
+		if(load){
+			trace(TraceProc, "preload 0x%llux", aa);
+			loadarenaclumps(load, aa);
 		}
 	}
 
-found:
-	ie->next = icache.heads[h];
-	icache.heads[h] = ie;
-
-	*ia = ie->ia;
-	*rac = ie->rac;
-
-	qunlock(&icache.lock);
-
-	if(load){
-		trace(TraceProc, "preload 0x%llux", aa);
-		loadarenaclumps(load, aa);
-	}
+out:
 	ms = msec() - ms;
 	addstat2(StatIcacheRead, 1, StatIcacheReadTime, ms);
 
-	return 0;
+	return ret;
 }
 
 /*
diff --git a/src/cmd/venti/srv/index.c b/src/cmd/venti/srv/index.c
index c69192a..87361aa 100644
--- a/src/cmd/venti/srv/index.c
+++ b/src/cmd/venti/srv/index.c
@@ -674,7 +674,10 @@
 {
 	int i, r, l, m, h, c, cc, type;
 
-	type = vttodisktype(otype);
+	if(otype == -1)
+		type = -1;
+	else
+		type = vttodisktype(otype);
 	l = 0;
 	r = n - 1;
 	while(l <= r){
@@ -692,7 +695,7 @@
 			}
 		}
 		cc = data[h + IEntryTypeOff];
-		if(type != cc){
+		if(type != cc && type != -1){
 			if(type > cc)
 				l = m + 1;
 			else
diff --git a/src/cmd/venti/srv/lump.c b/src/cmd/venti/srv/lump.c
index 13e6fe6..1db6271 100644
--- a/src/cmd/venti/srv/lump.c
+++ b/src/cmd/venti/srv/lump.c
@@ -5,9 +5,13 @@
 int			syncwrites = 0;
 int			queuewrites = 0;
 int			writestodevnull = 0;
+int			verifywrites = 0;
 
 static Packet		*readilump(Lump *u, IAddr *ia, u8int *score, int rac);
 
+/*
+ * Some of this logic is duplicated in hdisk.c
+ */
 Packet*
 readlump(u8int *score, int type, u32int size, int *cached)
 {
@@ -133,11 +137,13 @@
 	int rac;
 
 	if(lookupscore(u->score, u->type, &ia, &rac) == 0){
-		/* assume the data is here! XXX */
-		packetfree(p);
-		ms = msec() - ms;
-		addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
-		return 0;
+		if(verifywrites == 0){
+			/* assume the data is here! */
+			packetfree(p);
+			ms = msec() - ms;
+			addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
+			return 0;
+		}
 
 		/*
 		 * if the read fails,
diff --git a/src/cmd/venti/srv/mirrorarenas.c b/src/cmd/venti/srv/mirrorarenas.c
index 253b4ed..9591c3b 100644
--- a/src/cmd/venti/srv/mirrorarenas.c
+++ b/src/cmd/venti/srv/mirrorarenas.c
@@ -32,11 +32,46 @@
 	threadexitsall("usage");
 }
 
+char *tagged;
+
+void
+tag(char *fmt, ...)
+{
+	va_list arg;
+	
+	if(tagged){
+		free(tagged);
+		tagged = nil;
+	}
+	va_start(arg, fmt);
+	tagged = vsmprint(fmt, arg);
+	va_end(arg);
+}
+
+void
+chat(char *fmt, ...)
+{
+	va_list arg;
+
+	if(tagged){
+		write(1, tagged, strlen(tagged));
+		free(tagged);
+		tagged = nil;
+	}
+	va_start(arg, fmt);
+	vfprint(1, fmt, arg);
+	va_end(arg);
+}
+
+#pragma varargck argpos tag 1
+#pragma varargck argpos chat 1
+
+
 int
 ereadpart(Part *p, u64int offset, u8int *buf, u32int count)
 {
 	if(readpart(p, offset, buf, count) != count){
-		print("%T readpart %s at %#llux+%ud: %r\n", p->name, offset, count);
+		chat("%T readpart %s at %#llux+%ud: %r\n", p->name, offset, count);
 		return -1;
 	}
 	return 0;
@@ -46,7 +81,7 @@
 ewritepart(Part *p, u64int offset, u8int *buf, u32int count)
 {
 	if(writepart(p, offset, buf, count) != count){
-		print("%T writepart %s at %#llux+%ud: %r\n", p->name, offset, count);
+		chat("%T writepart %s at %#llux+%ud: %r\n", p->name, offset, count);
 		return -1;
 	}
 	return 0;
@@ -84,7 +119,7 @@
 	assert(astart <= end && end <= aend);
 
 	if(verbose && start != end)
-		print("%T   copy %,llud-%,llud %s\n", start, end, what);
+		chat("%T   copy %,llud-%,llud %s\n", start, end, what);
 
 	i = 0;
 	memset(w, 0, sizeof w);
@@ -146,7 +181,7 @@
 	assert(astart <= end && end <= aend);
 
 	if(verbose && start != end)
-		print("%T   copy %,llud-%,llud %s\n", start, end, what);
+		chat("%T   copy %,llud-%,llud %s\n", start, end, what);
 
 	for(o=start; o<end; o+=n){
 		n = sizeof tmp;
@@ -174,7 +209,7 @@
 	assert(start < end);
 
 	if(verbose)
-		print("%T   sha1 %,llud-%,llud\n", start, end);
+		chat("%T   sha1 %,llud-%,llud\n", start, end);
 
 	for(o=start; o<end; o+=n){
 		n = sizeof tmp;
@@ -217,31 +252,28 @@
 	
 	astart = base - blocksize;
 	aend = end + blocksize;
-	
-	shaoff = 0;
 
+	tag("%T %s (%,llud-%,llud)\n", sa->name, astart, aend);
+	
 	if(force){
 		copy(astart, aend, "all", nil);
 		return;
 	}
 
-	if(verbose)
-		print("%T %s (%,llud-%,llud)\n", sa->name, astart, aend);
-
 	if(sa->diskstats.sealed && da->diskstats.sealed && scorecmp(da->score, zeroscore) != 0){
 		if(scorecmp(sa->score, da->score) == 0)
 			return;
-		print("%T arena %s: sealed score mismatch %V vs %V\n", sa->name, sa->score, da->score);
+		chat("%T arena %s: sealed score mismatch %V vs %V\n", sa->name, sa->score, da->score);
 		status = "errors";
 		return;
 	}
 	if(da->diskstats.sealed && scorecmp(da->score, zeroscore) != 0){
-		print("%T arena %s: dst is sealed, src is not\n", sa->name);
+		chat("%T arena %s: dst is sealed, src is not\n", sa->name);
 		status = "errors";
 		return;
 	}
 	if(sa->diskstats.used < da->diskstats.used){
-		print("%T arena %s: src used %,lld < dst used %,lld\n", sa->name, sa->diskstats.used, da->diskstats.used);
+		chat("%T arena %s: src used %,lld < dst used %,lld\n", sa->name, sa->diskstats.used, da->diskstats.used);
 		status = "errors";
 		return;
 	}
@@ -331,16 +363,16 @@
 		sha1(buf, blocksize, da->score, ds);
 		if(scorecmp(sa->score, da->score) == 0){
 			if(verbose)
-				print("%T arena %s: %V\n", sa->name, da->score);
+				chat("%T arena %s: %V\n", sa->name, da->score);
 			scorecp(buf+blocksize-VtScoreSize, da->score);
 			if(ewritepart(dst, end, buf, blocksize) < 0)
 				return;
 		}else{
-			print("%T arena %s: sealing dst: score mismatch: %V vs %V\n", sa->name, sa->score, da->score);
+			chat("%T arena %s: sealing dst: score mismatch: %V vs %V\n", sa->name, sa->score, da->score);
 			memset(&xds, 0, sizeof xds);
 			asha1(dst, base-blocksize, end, &xds);
 			sha1(buf, blocksize, da->score, &xds);
-			print("%T   reseal: %V\n", da->score);
+			chat("%T   reseal: %V\n", da->score);
 			status = "errors";
 		}
 	}
@@ -383,7 +415,7 @@
 				hi = strtol(s, &s, 0);
 		}
 		if(*s != 0){
-			print("%T bad arena range: %s\n", s);
+			chat("%T bad arena range: %s\n", s);
 			continue;
 		}
 		for(i=lo; i<=hi; i++){
diff --git a/src/cmd/venti/srv/mkfile b/src/cmd/venti/srv/mkfile
index 2f9a89d..095a298 100644
--- a/src/cmd/venti/srv/mkfile
+++ b/src/cmd/venti/srv/mkfile
@@ -1,6 +1,4 @@
 <$PLAN9/src/mkhdr
-CC=9c
-
 
 LIBOFILES=\
 	arena.$O\
@@ -14,6 +12,7 @@
 	disksched.$O\
 	dump.$O\
 	graph.$O\
+	hdisk.$O\
 	httpd.$O\
 	icache.$O\
 	icachewrite.$O\
@@ -41,7 +40,7 @@
 
 SLIB=libvs.a
 
-LIB=$SLIB
+LIB=$SLIB $LIBDIR/libnventi.a
 
 HFILES=	dat.h\
 	fns.h\
@@ -49,22 +48,22 @@
 
 TARG=\
 	venti\
-	fmtarenas\
-	fmtbloom\
-	fmtisect\
-	fmtindex\
-	fixarenas\
 	buildindex\
 	checkarenas\
 	checkindex\
 	clumpstats\
 	findscore\
+	fixarenas\
+	fmtarenas\
+	fmtbloom\
+	fmtindex\
+	fmtisect\
 	mirrorarenas\
-	rdarena\
-	wrarena\
-	syncindex\
 	printarena\
+	rdarena\
+	syncindex\
 	verifyarena\
+	wrarena\
 
 OFILES=
 
@@ -72,82 +71,18 @@
 
 it:V: $O.venti
 
-$O.venti: # debugmalloc2.$O # debugmalloc.$O #_p9dir.$O debugmalloc.$O
-
 CLEANFILES=$CLEANFILES $SLIB
 
-<$PLAN9/src/mkmany
+<$PLAN9/src/cmd/mkmany
+
+CFLAGS=$CFLAGS -I.
 
 $SLIB: $LIBOFILES
-	$AR rvc $SLIB $LIBOFILES
+	ar rvc $SLIB $LIBOFILES
 
 # xml.c:D:	mkxml dat.h
 # 	./mkxml dat.h > xml.c
 
-ainstall:V: ${TARG:%=%.ainstall}
-
-%.ainstall:V:	$O.%
-	scp $prereq amsterdam:/usr/local/bin/venti/$stem
-
-test:VQ: ${TARG:%=o.%}
-	slay o.venti|rc
-	vtmp=/home/tmp
-	test -f $vtmp/arena || dd bs=1048576 count=100 if=/dev/zero of=$vtmp/arena
-	test -f $vtmp/bloom || dd bs=1048576 count=10 if=/dev/zero of=$vtmp/bloom
-	test -f $vtmp/isect || dd bs=1048576 count=10 if=/dev/zero of=$vtmp/isect
-	test -f $vtmp/check || dd bs=1048576 count=20 if=/dev/zero of=$vtmp/check
-	echo '**********' FMTARENAS
-	./o.fmtarenas -a 40M -b 8k arenas $vtmp/arena
-	echo '**********' FMTBLOOM
-	./o.fmtbloom -s 10M $vtmp/bloom
-	echo '**********' FMTISECT
-	./o.fmtisect -b 8k isect $vtmp/isect
-	(
-		echo index main
-		echo isect $vtmp/isect
-		echo arenas $vtmp/arena
-		echo bloom $vtmp/bloom
-		echo webroot $PLAN9/src/cmd/venti/srv/www
-		echo mem 64M
-		echo icmem 64M
-		echo bcmem 64M
-		echo queuewrites
-		echo addr 'tcp!*!17034'
-		echo httpaddr 'tcp!*!8001'
-	) >vtmp.conf
-	echo '**********' FMTINDEX
-	./o.fmtindex vtmp.conf
-	echo '**********' VENTI
-	./o.venti -c vtmp.conf >a 2>&1
-	echo '**********' VAC
-	venti='tcp!127.0.0.1!17034' export venti
-	9 time vac /usr/local/plan9/src >a.vac
-	case ${websync:-no} in
-	yes)
-		echo '**********' SYNC VIA WEB
-		hget http://127.0.0.1:8001/flushdcache
-		hget http://127.0.0.1:8001/flushicache
-		hget http://127.0.0.1:8001/flushdcache
-		echo '**********' KILL VENTI
-		killall -9 o.venti
-		;;
-	no)
-		echo '**********' KILL VENTI
-		killall -9 o.venti
-		echo '**********' SYNCINDEX
-		./o.syncindex -B64M -I64M -f vtmp.conf
-		;;
-	esac
-	echo '**********' CHECKINDEX
-	./o.checkindex -B64M vtmp.conf $vtmp/check >check.out
-	wc check.out
-
-luadisk.o: luadisk.c
-	gcc -c -ggdb -Wall -I/usr/include/lua50 luadisk.c
-
-libluadisk.so: luadisk.o
-	gcc -shared -o $target luadisk.o -llua50 -llualib50
-
-$O.xwrarena: xwrarena.$O
-	$LD -o $target xwrarena.$O 
+acid:D: lumpcache.acid
+	cat $prereq >$target
 
diff --git a/src/cmd/venti/srv/part.c b/src/cmd/venti/srv/part.c
index 1f8238c..a726dfd 100644
--- a/src/cmd/venti/srv/part.c
+++ b/src/cmd/venti/srv/part.c
@@ -197,14 +197,15 @@
 prwb(char *name, int fd, int isread, u64int offset, void *vbuf, u32int count, u32int blocksize)
 {
 	char *op;
-	u8int *buf, *tmp, *freetmp, *dst;
-	u32int c, delta, icount, opsize;
+	u8int *buf, *freetmp, *dst;
+	u32int icount, opsize;
 	int r;
 
-	icount = count;
-	buf = vbuf;
 
 #ifndef PLAN9PORT
+	USED(blocksize);
+	icount = count;
+	buf = vbuf;
 	op = isread ? "read" : "write";
 	dst = buf;
 	freetmp = nil;
@@ -223,8 +224,12 @@
 			goto Error;
 	}
 	return icount;
-#endif
+#else
+	u32int c, delta;
+	u8int *tmp;
 
+	icount = count;
+	buf = vbuf;
 	tmp = nil;
 	freetmp = nil;
 	opsize = blocksize;
@@ -343,6 +348,7 @@
 	if(freetmp)
 		free(freetmp);
 	return icount;
+#endif
 
 Error:
 	seterr(EAdmin, "%s %s offset 0x%llux count %ud buf %p returned %d: %r",
diff --git a/src/cmd/venti/srv/printarena.c b/src/cmd/venti/srv/printarena.c
index ba3a62f..da70a25 100644
--- a/src/cmd/venti/srv/printarena.c
+++ b/src/cmd/venti/srv/printarena.c
@@ -68,7 +68,7 @@
 	Arena *arena;
 	u64int offset, aoffset;
 	Part *part;
-	uchar buf[8192];
+	static uchar buf[8192];
 	ArenaHead head;
 
 	readonly = 1;	/* for part.c */
diff --git a/src/cmd/venti/srv/sortientry.c b/src/cmd/venti/srv/sortientry.c
index fc5e85e..b8b8e87 100644
--- a/src/cmd/venti/srv/sortientry.c
+++ b/src/cmd/venti/srv/sortientry.c
@@ -250,10 +250,7 @@
 		ib->bucks[i].buf = nil;
 	ib->off = (u64int)ib->chunks * ib->size;
 	free(ib->xbuf);
-if(0){
-	fprint(2, "ib->max = %lld\n", ib->max);
-	fprint(2, "ib->chunks = %ud\n", ib->chunks);
-}
+
 	ib->buf = MKN(u8int, ib->max + U32Size);
 	if(ib->buf == nil){
 		seterr(EOk, "out of memory allocating final sorting buffer; try more buckets");
@@ -270,7 +267,6 @@
 		tot += n;
 	}
 	return tot;
-	return 0;
 }
 
 /*
@@ -352,7 +348,7 @@
 	if(m == 0)
 		m = ib->usable;
 	if(0) if(ib->bucks[b].total)
-		fprint(2, "\tbucket %d: %d entries\n", b, ib->bucks[b].total/IEntrySize);
+		fprint(2, "\tbucket %d: %lld entries\n", b, ib->bucks[b].total/IEntrySize);
 	while(head != TWID32){
 		if(readpart(ib->part, (u64int)head * ib->size, &ib->buf[n], m+U32Size) < 0){
 			seterr(EOk, "can't read index sort bucket: %r");
diff --git a/src/cmd/venti/srv/stats.c b/src/cmd/venti/srv/stats.c
index 874f7d2..3a66bf6 100644
--- a/src/cmd/venti/srv/stats.c
+++ b/src/cmd/venti/srv/stats.c
@@ -149,8 +149,8 @@
 binstats(long (*fn)(Stats *s0, Stats *s1, void *arg), void *arg,
 	long t0, long t1, Statbin *bin, int nbin)
 {
-	long t, xt0, te, v;
-	int i, j, lo, hi, m, oj;
+	long xt0, t, te, v;
+	int i, j, lo, hi, m;
 	vlong tot;
 	Statbin *b;
 	
@@ -177,7 +177,6 @@
 			lo = m;
 	}
 	xt0 = stathist[lo%nstathist].now;
-	if(0) fprint(2, "bsearch found %ld\n", xt0);
 	if(xt0 >= t1){
 		/* no samples */
 		memset(bin, 0, nbin*sizeof bin[0]);
@@ -185,15 +184,12 @@
 	}
 
 	hi = stattime+nstathist;
-	te = t0;
 	j = lo+1;
 	for(i=0; i<nbin; i++){
-		t = te;
 		te = t0 + (t1-t0)*i/nbin;
 		b = &bin[i];
 		memset(b, 0, sizeof *b);
 		tot = 0;
-		oj = j;
 		for(; j<hi && stathist[j%nstathist].now<te; j++){
 			v = fn(&stathist[(j-1)%nstathist], &stathist[j%nstathist], arg);
 			if(b->nsamp==0 || v < b->min)
@@ -203,7 +199,6 @@
 			tot += v;
 			b->nsamp++;
 		}
-		if(0) fprint(2, "bin%d: %ld to %ld; %d to %d - %d samples\n", i, t, te, oj, j, b->nsamp);
 		if(b->nsamp)
 			b->avg = tot / b->nsamp;
 		if(b->nsamp==0 && i>0)
diff --git a/src/cmd/venti/srv/syncarena.c b/src/cmd/venti/srv/syncarena.c
index 89546f5..be950e9 100644
--- a/src/cmd/venti/srv/syncarena.c
+++ b/src/cmd/venti/srv/syncarena.c
@@ -64,7 +64,6 @@
 		if(lump == nil){
 			fprint(2, "%s: clump=%d failed to read correctly: %r\n", arena->name, clump);
 			break;
-			err |= SyncDataErr;
 		}else if(cl.info.type != VtCorruptType){
 			scoremem(score, lump->data, cl.info.uncsize);
 			if(scorecmp(cl.info.score, score) != 0){
diff --git a/src/cmd/venti/srv/syncindex0.c b/src/cmd/venti/srv/syncindex0.c
index e214d71..1a6aa7d 100644
--- a/src/cmd/venti/srv/syncindex0.c
+++ b/src/cmd/venti/srv/syncindex0.c
@@ -123,7 +123,6 @@
 	Arena *arena;
 	AState as;
 	u64int a;
-	u32int clump;
 	int i, e, e1, ok, ok1, flush;
 
 	ok = 0;
@@ -144,11 +143,18 @@
 			e1 &= ~(SyncHeader|SyncCIZero|SyncCIErr);
 		if(e1 == SyncHeader)
 			fprint(2, "arena %s: header is out-of-date\n", arena->name);
-		clump = arena->diskstats.clumps;
 		if(e1)
 			ok = -1;
 		else{
-			ok1 = syncarenaindex(ix, arena, clump, a + ix->amap[i].start, fix, &flush, check);
+			/*
+			 * use diskstats not memstats here, because diskstats
+			 * is what has been indexed; memstats is what has 
+			 * made it to disk (confusing names).
+			 */
+			ok1 = syncarenaindex(ix, arena,
+					arena->diskstats.clumps,
+					ix->amap[i].start + arena->diskstats.used,
+					fix, &flush, check);
 			if(ok1 < 0)
 				fprint(2, "syncarenaindex: %r\n");
 fprint(2, "arena %s: wbarena in syncindex\n", arena->name);
diff --git a/src/cmd/venti/srv/zblock.c b/src/cmd/venti/srv/zblock.c
index 5d9bb3d..87c3176 100644
--- a/src/cmd/venti/srv/zblock.c
+++ b/src/cmd/venti/srv/zblock.c
@@ -6,7 +6,9 @@
 fmtzbinit(Fmt *f, ZBlock *b)
 {
 	memset(f, 0, sizeof *f);
+#ifdef PLAN9PORT
 	fmtlocaleinit(f, nil, nil, nil);
+#endif
 	f->start = b->data;
 	f->to = f->start;
 	f->stop = (char*)f->start + b->len;
diff --git a/src/cmd/venti/srv/zeropart.c b/src/cmd/venti/srv/zeropart.c
index 7602627..b94b728 100644
--- a/src/cmd/venti/srv/zeropart.c
+++ b/src/cmd/venti/srv/zeropart.c
@@ -9,7 +9,7 @@
 	u64int addr;
 	int w;
 
-	fprint(2, "clearing the partition\n");
+	fprint(2, "clearing %s\n", part->name);
 	b = alloczblock(MaxIoSize, 1, blocksize);
 
 	w = 0;