tsync with mit plan 9 version - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 27d28098203579f0735ba6400641e9be94eb12f8
 (DIR) parent 33433b3fde56d9b3ac6de6ee2584416b82bc856f
 (HTM) Author: rsc <devnull@localhost>
       Date:   Sat, 21 Apr 2007 19:40:55 +0000
       
       sync with mit plan 9 version
       
       Diffstat:
         M src/cmd/venti/devnull.c             |       3 +--
         M src/cmd/venti/mkfile                |       3 +++
         M src/cmd/venti/mkroot.c              |      14 ++++++++------
         M src/cmd/venti/randtest.c            |       1 +
         M src/cmd/venti/srv/bloom.c           |      13 +++++++++----
         M src/cmd/venti/srv/checkarenas.c     |       2 +-
         M src/cmd/venti/srv/checkindex.c      |       9 ++++-----
         M src/cmd/venti/srv/cmparenas.c       |      52 +++++++++++++++++++++++++++++--
         M src/cmd/venti/srv/conv.c            |      19 ++++++++++++++-----
         M src/cmd/venti/srv/dat.h             |       2 +-
         M src/cmd/venti/srv/dcache.c          |      16 ++++++++++++++--
         M src/cmd/venti/srv/fixarenas.c       |       2 --
         M src/cmd/venti/srv/fns.h             |       8 ++++++++
         M src/cmd/venti/srv/graph.c           |      11 +----------
         M src/cmd/venti/srv/httpd.c           |     288 ++++++++++++++++---------------
         M src/cmd/venti/srv/icache.c          |     146 ++++++++++++++++++-------------
         M src/cmd/venti/srv/index.c           |       7 +++++--
         M src/cmd/venti/srv/lump.c            |      16 +++++++++++-----
         M src/cmd/venti/srv/mirrorarenas.c    |      66 +++++++++++++++++++++++--------
         M src/cmd/venti/srv/mkfile            |      95 +++++--------------------------
         M src/cmd/venti/srv/part.c            |      16 +++++++++++-----
         M src/cmd/venti/srv/printarena.c      |       2 +-
         M src/cmd/venti/srv/sortientry.c      |       8 ++------
         M src/cmd/venti/srv/stats.c           |       9 ++-------
         M src/cmd/venti/srv/syncarena.c       |       1 -
         M src/cmd/venti/srv/syncindex0.c      |      12 +++++++++---
         M src/cmd/venti/srv/zblock.c          |       2 ++
         M src/cmd/venti/srv/zeropart.c        |       2 +-
       
       28 files changed, 455 insertions(+), 370 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/venti/devnull.c b/src/cmd/venti/devnull.c
       t@@ -30,7 +30,6 @@ threadmain(int argc, char **argv)
                VtReq *r;
                VtSrv *srv;
                char *address;
       -        Packet *p;
        
                fmtinstall('V', vtscorefmt);
                fmtinstall('F', vtfcallfmt);
       t@@ -50,7 +49,7 @@ threadmain(int argc, char **argv)
        
                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;
 (DIR) diff --git a/src/cmd/venti/mkfile b/src/cmd/venti/mkfile
       t@@ -13,3 +13,6 @@ BIN=$BIN/venti
        <$PLAN9/src/mkmany
        <$PLAN9/src/mkdirs
        
       +
       +extra:V: $O.devnull $O.mkroot $O.randtest $O.readlist $O.ro $O.root
       +
 (DIR) diff --git a/src/cmd/venti/mkroot.c b/src/cmd/venti/mkroot.c
       t@@ -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;
        
       t@@ -31,14 +32,15 @@ threadmain(int argc, char *argv[])
                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);
        
 (DIR) diff --git a/src/cmd/venti/randtest.c b/src/cmd/venti/randtest.c
       t@@ -35,6 +35,7 @@ wr(char *buf, char *buf2)
                uchar score[VtScoreSize], score2[VtScoreSize];
                DigestState ds;
        
       +        USED(buf2);
                memset(&ds, 0, sizeof ds);
                if(doublecheck)
                        sha1((uchar*)buf, blocksize, score, &ds);
 (DIR) diff --git a/src/cmd/venti/srv/bloom.c b/src/cmd/venti/srv/bloom.c
       t@@ -27,7 +27,7 @@ bloominit(Bloom *b, vlong vsize, u8int *data)
                                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;
        }
       t@@ -47,11 +47,17 @@ readbloom(Part *p)
                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;
        }
        
       t@@ -61,7 +67,6 @@ resetbloom(Bloom *b)
                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);
       t@@ -145,7 +150,7 @@ _markbloomfilter(Bloom *b, u8int *score)
                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++;
       t@@ -169,7 +174,7 @@ _inbloomfilter(Bloom *b, u8int *score)
                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;
 (DIR) diff --git a/src/cmd/venti/srv/checkarenas.c b/src/cmd/venti/srv/checkarenas.c
       t@@ -112,7 +112,7 @@ threadmain(int argc, char *argv[])
                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);
        
 (DIR) diff --git a/src/cmd/venti/srv/checkindex.c b/src/cmd/venti/srv/checkindex.c
       t@@ -116,8 +116,7 @@ u64int found = 0;
                if(b == nil || z == nil || ies == nil){
                        werrstr("allocating: %r");
                        ok = -1;
       -                goto breakout;
       -                return -1;
       +                goto out;
                }
                ok = 0;
                next = 0;
       t@@ -138,7 +137,7 @@ u64int found = 0;
                                                }
                                                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)
       t@@ -150,14 +149,14 @@ u64int found = 0;
                                        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);
 (DIR) diff --git a/src/cmd/venti/srv/cmparenas.c b/src/cmd/venti/srv/cmparenas.c
       t@@ -51,21 +51,64 @@ readblock(int fd, uchar *buf, int n)
                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);
        
                /*
       t@@ -104,6 +147,9 @@ cmparena(char *name, vlong len)
                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
 (DIR) diff --git a/src/cmd/venti/srv/conv.c b/src/cmd/venti/srv/conv.c
       t@@ -34,7 +34,7 @@ fmtmagic(char *s, u32int m)
                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;
        }
        
       t@@ -61,7 +61,7 @@ unpackarenapart(ArenaPart *ap, u8int *buf)
        
                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;
       t@@ -112,7 +112,7 @@ unpackarena(Arena *arena, u8int *buf)
        
                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;
       t@@ -276,10 +276,15 @@ unpackarenahead(ArenaHead *head, u8int *buf)
                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;
       t@@ -497,7 +502,7 @@ unpackisect(ISect *is, u8int *buf)
        
                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;
                }
       t@@ -665,7 +670,7 @@ unpackbloomhead(Bloom *b, u8int *buf)
        
                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;
       t@@ -682,6 +687,10 @@ unpackbloomhead(Bloom *b, u8int *buf)
        
                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");
 (DIR) diff --git a/src/cmd/venti/srv/dat.h b/src/cmd/venti/srv/dat.h
       t@@ -696,7 +696,7 @@ struct Bloom
                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;
 (DIR) diff --git a/src/cmd/venti/srv/dcache.c b/src/cmd/venti/srv/dcache.c
       t@@ -169,11 +169,24 @@ raproc(void *v)
                        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;
       t@@ -185,7 +198,6 @@ dreadahead(Part *part, u64int addr, int miss)
                        int dir;
                } lastra;
        
       -return;
                if(miss){
                        if(lastmiss.part==part && lastmiss.addr==addr-dcache.size){
                        XRa:
 (DIR) diff --git a/src/cmd/venti/srv/fixarenas.c b/src/cmd/venti/srv/fixarenas.c
       t@@ -976,7 +976,6 @@ ltreewalk(int *p, uchar *score)
                        else
                                p = &cibuf[*p].left;
                }
       -        return nil;         /* stupid 8c */
        }
        
        void
       t@@ -1024,7 +1023,6 @@ haveclump(uchar *score)
                        else
                                p = cibuf[p].left;
                }
       -        return 0;        /* stupid 8c */
        }
        
        int
 (DIR) diff --git a/src/cmd/venti/srv/fns.h b/src/cmd/venti/srv/fns.h
       t@@ -51,6 +51,13 @@ void                freezblock(ZBlock *b);
        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);
       t@@ -89,6 +96,7 @@ DBlock        *loadibucket(Index *index, u8int *score, ISect **is, u32int *buck, IBucke
        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*);
 (DIR) diff --git a/src/cmd/venti/srv/graph.c b/src/cmd/venti/srv/graph.c
       t@@ -111,7 +111,7 @@ scalept(int val, int valmin, int valmax, int ptmin, int ptmax)
        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 */
       t@@ -178,7 +178,6 @@ statgraph(Graph *g)
                        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)
       t@@ -187,16 +186,8 @@ statgraph(Graph *g)
                        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)
 (DIR) diff --git a/src/cmd/venti/srv/httpd.c b/src/cmd/venti/srv/httpd.c
       t@@ -36,7 +36,6 @@ static        int                hicachekick(HConnect *c);
        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);
       t@@ -61,15 +60,15 @@ httpdinit(char *address, char *dir)
                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;
       t@@ -168,6 +167,11 @@ httpproc(void *v)
                         */
                        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);
       t@@ -179,6 +183,7 @@ httpproc(void *v)
                        }
                        ok = fromwebdir(c);
                found:
       +                hflush(&c->hout);
                        if(c->head.closeit)
                                ok = -1;
                        hreqcleanup(c);
       t@@ -191,6 +196,27 @@ httpproc(void *v)
                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)
        {
       t@@ -217,8 +243,8 @@ preq(HConnect *c)
                return 0;
        }
        
       -static int
       -preqtype(HConnect *c, char *type)
       +int
       +hsettype(HConnect *c, char *type)
        {
                Hio *hout;
                int r;
       t@@ -243,10 +269,16 @@ preqtype(HConnect *c, char *type)
                return 0;
        }
        
       -static int
       -preqtext(HConnect *c)
       +int
       +hsethtml(HConnect *c)
       +{
       +        return hsettype(c, "text/html; charset=utf-8");
       +}
       +
       +int
       +hsettext(HConnect *c)
        {
       -        return preqtype(c, "text/plain");
       +        return hsettype(c, "text/plain; charset=utf-8");
        }
        
        static int
       t@@ -274,8 +306,8 @@ herror(HConnect *c)
                return hflush(hout);
        }
                
       -static int
       -notfound(HConnect *c)
       +int
       +hnotfound(HConnect *c)
        {
                int r;
        
       t@@ -305,16 +337,16 @@ fromwebdir(HConnect *c)
                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){
       t@@ -325,7 +357,7 @@ reopen:
                                goto reopen;
                        }
                        free(d);
       -                return notfound(c);
       +                return hnotfound(c);
                }
                free(d);
                p = buf+strlen(buf);
       t@@ -337,7 +369,7 @@ reopen:
                                break;
                        }
                }
       -        if(preqtype(c, type) < 0){
       +        if(hsettype(c, type) < 0){
                        close(fd);
                        return 0;
                }
       t@@ -372,54 +404,41 @@ static struct
        };
        
        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);
       -
       -        s = estrdup(c->req.uri);
       -        nf = getfields(s+strlen("/set/"), f, nelem(f), 1, "/");
       +        if(hsettext(c) < 0)
       +                return -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;
       +        }
       +
       +        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;
                }
       -        return notfound(c);
       +        
       +        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
       t@@ -428,7 +447,7 @@ estats(HConnect *c)
                Hio *hout;
                int r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
        
       t@@ -503,7 +522,7 @@ sindex(HConnect *c)
                vlong clumps, cclumps, uncsize, used, size;
                int i, r, active;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -567,7 +586,7 @@ hempty(HConnect *c)
                Hio *hout;
                int r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -586,7 +605,7 @@ hlcacheempty(HConnect *c)
                Hio *hout;
                int r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -603,7 +622,7 @@ hicacheempty(HConnect *c)
                Hio *hout;
                int r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -620,7 +639,7 @@ hdcacheempty(HConnect *c)
                Hio *hout;
                int r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -636,7 +655,7 @@ hicachekick(HConnect *c)
                Hio *hout;
                int r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -653,7 +672,7 @@ hdcachekick(HConnect *c)
                Hio *hout;
                int r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -669,7 +688,7 @@ hicacheflush(HConnect *c)
                Hio *hout;
                int r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -686,7 +705,7 @@ hdcacheflush(HConnect *c)
                Hio *hout;
                int r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -704,7 +723,7 @@ dindex(HConnect *c)
                Index *ix;
                int i, r;
        
       -        r = preqtext(c);
       +        r = hsettext(c);
                if(r < 0)
                        return r;
                hout = &c->hout;
       t@@ -772,6 +791,23 @@ pctdiffgraph(Stats *s, Stats *t, void *va)
        }
        
        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;
       t@@ -928,79 +964,59 @@ dotextbin(Hio *io, Graph *g)
        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;
       t@@ -1010,7 +1026,7 @@ if(0) fprint(2, "graph %s\n" ,s);
                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);
       t@@ -1018,18 +1034,16 @@ if(0) fprint(2, "graph %s\n" ,s);
                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);
       t@@ -1042,15 +1056,13 @@ xlog(HConnect *c)
                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;
                }
       t@@ -1063,7 +1075,7 @@ xlog(HConnect *c)
        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);
       t@@ -1158,7 +1170,7 @@ vtloghlist(Hio *h)
                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");
        }
 (DIR) diff --git a/src/cmd/venti/srv/icache.c b/src/cmd/venti/srv/icache.c
       t@@ -86,99 +86,119 @@ fprint(2, "seed index cache with arena @%llud, (map %llud), %d clumps\n", arena-
                }
        }
        
       -/*
       -ZZZ need to think about evicting the correct IEntry,
       -and writing back the wtime.
       - * look up data score in the index cache
       - * if this fails, pull it in from the disk index table, if it exists.
       - *
       - * must be called with the lump for this score locked
       - */
        int
       -lookupscore(u8int *score, int type, IAddr *ia, int *rac)
       +_lookupscore(u8int *score, int type, IAddr *ia, int *rac)
        {
       -        IEntry d, *ie, *last;
                u32int h;
       -        u64int aa;
       -        Arena *load;
       -        int i;
       -        uint ms;
       -
       -        load = nil;
       -        aa = 0;
       -        ms = msec();
       -        
       -        trace(TraceLump, "lookupscore %V.%d", score, type);
       +        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 && scorecmp(ie->score, score)==0){
       +                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);
       -                        ie->rac = 1;
       +                        if(rac)
       +                                ie->rac = 1;
                                trace(TraceLump, "lookupscore incache");
       -                        goto found;
       +                        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;
       +}
        
       -        if(loadientry(mainindex, score, type, &d) < 0){
       -                ms = msec() - ms;
       -                addstat2(StatIcacheRead, 1, StatIcacheReadTime, ms);
       -                return -1;
       -        }
       -
       -        addstat(StatIcacheFill, 1);
        
       -        trace(TraceLump, "lookupscore loaded");
       +/*
       +ZZZ need to think about evicting the correct IEntry,
       +and writing back the wtime.
       + * look up data score in the index cache
       + * if this fails, pull it in from the disk index table, if it exists.
       + *
       + * must be called with the lump for this score locked
       + */
       +int
       +lookupscore(u8int *score, int type, IAddr *ia, int *rac)
       +{
       +        IEntry d, *ie;
       +        u32int h;
       +        u64int aa;
       +        Arena *load;
       +        int i, ret;
       +        uint ms;
        
       -        /*
       -         * no one else can load an entry for this score,
       -         * since we have the overall score lock.
       -         */
       -        qlock(&icache.lock);
       +        aa = 0;
       +        ms = msec();
       +        
       +        trace(TraceLump, "lookupscore %V.%d", score, type);
        
       -        /*
       -         * 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;
       +        ret = 0;
       +        if(_lookupscore(score, type, ia, rac) < 0){
       +                if(loadientry(mainindex, score, type, &d) < 0){
       +                        ret = -1;
       +                        goto out;
                        }
       -        }
       -
       -found:
       -        ie->next = icache.heads[h];
       -        icache.heads[h] = ie;
        
       -        *ia = ie->ia;
       -        *rac = ie->rac;
       +                /* failed in cache but found on disk - fill cache. */
       +                trace(TraceLump, "lookupscore loaded");
       +                addstat(StatIcacheFill, 1);
        
       -        qunlock(&icache.lock);
       -
       -        if(load){
       -                trace(TraceProc, "preload 0x%llux", aa);
       -                loadarenaclumps(load, aa);
       +                /*
       +                 * 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);
       +                }
                }
       +
       +out:
                ms = msec() - ms;
                addstat2(StatIcacheRead, 1, StatIcacheReadTime, ms);
        
       -        return 0;
       +        return ret;
        }
        
        /*
 (DIR) diff --git a/src/cmd/venti/srv/index.c b/src/cmd/venti/srv/index.c
       t@@ -674,7 +674,10 @@ bucklook(u8int *score, int otype, u8int *data, int n)
        {
                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){
       t@@ -692,7 +695,7 @@ bucklook(u8int *score, int otype, u8int *data, int n)
                                }
                        }
                        cc = data[h + IEntryTypeOff];
       -                if(type != cc){
       +                if(type != cc && type != -1){
                                if(type > cc)
                                        l = m + 1;
                                else
 (DIR) diff --git a/src/cmd/venti/srv/lump.c b/src/cmd/venti/srv/lump.c
       t@@ -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)
        {
       t@@ -133,11 +137,13 @@ writeqlump(Lump *u, Packet *p, int creator, uint ms)
                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,
 (DIR) diff --git a/src/cmd/venti/srv/mirrorarenas.c b/src/cmd/venti/srv/mirrorarenas.c
       t@@ -32,11 +32,46 @@ usage(void)
                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;
       t@@ -46,7 +81,7 @@ int
        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;
       t@@ -84,7 +119,7 @@ copy(uvlong start, uvlong end, char *what, DigestState *ds)
                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);
       t@@ -146,7 +181,7 @@ copy1(uvlong start, uvlong end, char *what, DigestState *ds)
                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;
       t@@ -174,7 +209,7 @@ asha1(Part *p, uvlong start, uvlong end, DigestState *ds)
                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;
       t@@ -217,31 +252,28 @@ mirror(Arena *sa, Arena *da)
                
                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;
                }
       t@@ -331,16 +363,16 @@ mirror(Arena *sa, Arena *da)
                        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";
                        }
                }
       t@@ -383,7 +415,7 @@ mirrormany(ArenaPart *sp, ArenaPart *dp, char *range)
                                        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++){
 (DIR) diff --git a/src/cmd/venti/srv/mkfile b/src/cmd/venti/srv/mkfile
       t@@ -1,6 +1,4 @@
        <$PLAN9/src/mkhdr
       -CC=9c
       -
        
        LIBOFILES=\
                arena.$O\
       t@@ -14,6 +12,7 @@ LIBOFILES=\
                disksched.$O\
                dump.$O\
                graph.$O\
       +        hdisk.$O\
                httpd.$O\
                icache.$O\
                icachewrite.$O\
       t@@ -41,7 +40,7 @@ LIBOFILES=\
        
        SLIB=libvs.a
        
       -LIB=$SLIB
       +LIB=$SLIB $LIBDIR/libnventi.a
        
        HFILES=        dat.h\
                fns.h\
       t@@ -49,22 +48,22 @@ HFILES=        dat.h\
        
        TARG=\
                venti\
       -        fmtarenas\
       -        fmtbloom\
       -        fmtisect\
       -        fmtindex\
       -        fixarenas\
                buildindex\
                checkarenas\
                checkindex\
                clumpstats\
                findscore\
       +        fixarenas\
       +        fmtarenas\
       +        fmtbloom\
       +        fmtindex\
       +        fmtisect\
                mirrorarenas\
       +        printarena\
                rdarena\
       -        wrarena\
                syncindex\
       -        printarena\
                verifyarena\
       +        wrarena\
        
        OFILES=
        
       t@@ -72,82 +71,18 @@ BIN=$BIN/venti
        
        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
        
 (DIR) diff --git a/src/cmd/venti/srv/part.c b/src/cmd/venti/srv/part.c
       t@@ -197,14 +197,15 @@ int
        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;
       t@@ -223,8 +224,12 @@ prwb(char *name, int fd, int isread, u64int offset, void *vbuf, u32int count, u3
                                goto Error;
                }
                return icount;
       -#endif
       +#else
       +        u32int c, delta;
       +        u8int *tmp;
        
       +        icount = count;
       +        buf = vbuf;
                tmp = nil;
                freetmp = nil;
                opsize = blocksize;
       t@@ -343,6 +348,7 @@ print("FAILED isread=%d r=%d count=%d blocksize=%d\n", isread, r, count, blocksi
                if(freetmp)
                        free(freetmp);
                return icount;
       +#endif
        
        Error:
                seterr(EAdmin, "%s %s offset 0x%llux count %ud buf %p returned %d: %r",
 (DIR) diff --git a/src/cmd/venti/srv/printarena.c b/src/cmd/venti/srv/printarena.c
       t@@ -68,7 +68,7 @@ threadmain(int argc, char *argv[])
                Arena *arena;
                u64int offset, aoffset;
                Part *part;
       -        uchar buf[8192];
       +        static uchar buf[8192];
                ArenaHead head;
        
                readonly = 1;        /* for part.c */
 (DIR) diff --git a/src/cmd/venti/srv/sortientry.c b/src/cmd/venti/srv/sortientry.c
       t@@ -250,10 +250,7 @@ sortiebucks(IEBucks *ib)
                        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");
       t@@ -270,7 +267,6 @@ if(0){
                        tot += n;
                }
                return tot;
       -        return 0;
        }
        
        /*
       t@@ -352,7 +348,7 @@ readiebuck(IEBucks *ib, int b)
                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");
 (DIR) diff --git a/src/cmd/venti/srv/stats.c b/src/cmd/venti/srv/stats.c
       t@@ -149,8 +149,8 @@ void
        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;
                
       t@@ -177,7 +177,6 @@ binstats(long (*fn)(Stats *s0, Stats *s1, void *arg), void *arg,
                                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]);
       t@@ -185,15 +184,12 @@ binstats(long (*fn)(Stats *s0, Stats *s1, void *arg), void *arg,
                }
        
                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)
       t@@ -203,7 +199,6 @@ binstats(long (*fn)(Stats *s0, Stats *s1, void *arg), void *arg,
                                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)
 (DIR) diff --git a/src/cmd/venti/srv/syncarena.c b/src/cmd/venti/srv/syncarena.c
       t@@ -64,7 +64,6 @@ syncarena(Arena *arena, u64int start, u32int n, int zok, int fix)
                        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){
 (DIR) diff --git a/src/cmd/venti/srv/syncindex0.c b/src/cmd/venti/srv/syncindex0.c
       t@@ -123,7 +123,6 @@ syncindex(Index *ix, int fix, int mustflush, int check)
                Arena *arena;
                AState as;
                u64int a;
       -        u32int clump;
                int i, e, e1, ok, ok1, flush;
        
                ok = 0;
       t@@ -144,11 +143,18 @@ syncindex(Index *ix, int fix, int mustflush, int check)
                                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);
 (DIR) diff --git a/src/cmd/venti/srv/zblock.c b/src/cmd/venti/srv/zblock.c
       t@@ -6,7 +6,9 @@ void
        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;
 (DIR) diff --git a/src/cmd/venti/srv/zeropart.c b/src/cmd/venti/srv/zeropart.c
       t@@ -9,7 +9,7 @@ zeropart(Part *part, int blocksize)
                u64int addr;
                int w;
        
       -        fprint(2, "clearing the partition\n");
       +        fprint(2, "clearing %s\n", part->name);
                b = alloczblock(MaxIoSize, 1, blocksize);
        
                w = 0;