Update creepy with a somewhat tested version of 9pix. Beware this is not yet to be trusted to keep your files. Reference: /n/patches.lsub.org/patch/c9pix Date: Thu Jun 7 11:49:10 CES 2012 Signed-off-by: nemo@lsub.org # rm /sys/src/cmd/creepy/guide # rm /sys/src/cmd/creepy/ix.h # rm /sys/src/cmd/creepy/ixcall.c --- /sys/src/cmd/creepy/9p.c Mon May 21 11:20:09 2012 +++ /sys/src/cmd/creepy/9p.c Thu Jun 7 10:51:51 2012 @@ -9,6 +9,41 @@ ropen(Rpc*), rcreate(Rpc*), rread(Rpc*), rwrite(Rpc*), rclunk(Rpc*), rremove(Rpc*), rstat(Rpc*), rwstat(Rpc*); +char* npcallname[Tmax] = +{ + [Tversion] "Tversion", + [Rversion] "Rversion", + [Tauth] "Tauth", + [Rauth] "Rauth", + [Tattach] "Tattach", + [Rattach] "Rattach", + [Terror] "Terror", + [Rerror] "Rerror", + [Tflush] "Tflush", + [Rflush] "Rflush", + [Twalk] "Twalk", + [Rwalk] "Rwalk", + [Topen] "Topen", + [Ropen] "Ropen", + [Tcreate] "Tcreate", + [Rcreate] "Rcreate", + [Tread] "Tread", + [Rread] "Rread", + [Twrite] "Twrite", + [Rwrite] "Rwrite", + [Tclunk] "Tclunk", + [Rclunk] "Rclunk", + [Tremove] "Tremove", + [Rremove] "Rremove", + [Tstat] "Tstat", + [Rstat] "Rstat", + [Twstat] "Twstat", + [Rwstat] "Rwstat", +}; + +vlong npcalltime[Tmax]; +ulong npncalls[Tmax]; + static void (*fcalls[])(Rpc*) = { @@ -41,13 +76,13 @@ if(verb == 0) return s; for(i = 0; i < nelem(fcalls); i++) - if(fcalls[i] != nil && ncalls[i] > 0){ + if(fcalls[i] != nil && npncalls[i] > 0){ s = seprint(s, e, "%-8s\t%5uld calls\t%11ulld µs per call\n", - callname[i], ncalls[i], - (calltime[i]/ncalls[i])/1000); + npcallname[i], npncalls[i], + (npcalltime[i]/npncalls[i])/1000); if(clr){ - ncalls[i] = 0; - calltime[i] = 0; + npncalls[i] = 0; + npcalltime[i] = 0; } } return s; @@ -115,7 +150,7 @@ break; if(r != nil){ r->flushed = 1; - if(r->t.type == Tread && r->fid->consrc != nil) + if(r->t.type == Tread && r->fid != nil && r->fid->consrc != nil) nbsendp(r->fid->consrc, nil); } xqunlock(&rpc->cli->rpclk); @@ -190,6 +225,12 @@ char buf[ERRMAX]; fid = newfid(rpc->cli, rpc->t.fid); + if(catcherror()){ + rpc->fid = nil; + putfid(fid); + putfid(fid); /* clunk */ + error(nil); + } rpc->fid = fid; afid = nil; if(!rpc->cli->noauth){ @@ -221,6 +262,8 @@ if(rpc->cli->uid == -1) rpc->cli->uid = rpc->fid->uid; + + noerror(); } static void @@ -633,7 +676,7 @@ rpc = v; cli = rpc->cli; - threadsetname("rpcworker9p %s %R", cli->addr, rpc); + threadsetname("rpcworker9p"); dPprint("%s starting\n", threadgetname()); if(*aux == nil){ @@ -672,6 +715,7 @@ } if(catcherror()){ mbput(fahead); + xqunlock(&cli->wlk); error(nil); } @@ -688,10 +732,14 @@ }else dprint("flushed: %F\n", &rpc->r); if(fs->profile) - calltime[rpc->t.type] += nsec() - rpc->t0; - ncalls[rpc->t.type]++; + npcalltime[rpc->t.type] += nsec() - rpc->t0; + npncalls[rpc->t.type]++; + noerror(); xqunlock(&cli->wlk); - + if(catcherror()){ + mbput(fahead); + error(nil); + } if(fs->halt.ref > 0 && decref(&fs->halt) == 0){ warn("halted"); threadexitsall(nil); @@ -711,7 +759,6 @@ if(errstacksize() != nerr) fatal("%s: unbalanced error stack", threadgetname()); noerror(); - threadsetname("rpcworker9p"); return nil; } --- /sys/src/cmd/creepy/9pix.c Mon May 21 11:20:09 2012 +++ /sys/src/cmd/creepy/9pix.c Thu Jun 7 10:51:51 2012 @@ -53,7 +53,7 @@ }ARGEND; if(argc != 1) usage(); - if(srv == nil || addr == nil){ + if(srv == nil && addr == nil){ addr = "tcp!*!9fs"; srv = "9pix"; } @@ -61,7 +61,7 @@ if(dbg['d']) dbg['Z'] = 1; - threadsetname("9pix %s", dev); + threadsetname("main"); outofmemoryexits(1); workerthreadcreate = proccreate; fmtinstall('H', mbfmt); --- /sys/src/cmd/creepy/all.h Mon May 14 11:06:19 2012 +++ /sys/src/cmd/creepy/all.h Thu Jun 7 10:51:51 2012 @@ -6,10 +6,10 @@ #include #include #include +#include #include "conf.h" #include "dbg.h" #include "dk.h" -#include "ix.h" #include "net.h" #include "fns.h" --- /sys/src/cmd/creepy/arch.c Tue May 22 18:19:10 2012 +++ /sys/src/cmd/creepy/arch.c Thu Jun 7 10:51:51 2012 @@ -133,6 +133,10 @@ f = dbget(DBfile, addr); noerror(); xrlock(f->mf); + if(f->d.mode&DMTMP){ + xrunlock(f->mf); + return; + } dVprint("archdent %N\n", f->mf->name); if(catcherror()){ warn("archdent: %N: %r", f->mf->name); --- /sys/src/cmd/creepy/conf.h Tue May 22 18:21:44 2012 +++ /sys/src/cmd/creepy/conf.h Thu Jun 7 10:51:51 2012 @@ -44,6 +44,9 @@ Fidhashsz = 97, /* size of the fid hash size */ Uhashsz = 97, + Nsyncprocs = 20, /* # of concurrent writes to disk */ + /* could be increased up to 128 for aoe */ + Rpcspercli = 20, /* != 0 places a limit */ Nlstats = 1009, /* # of lock profiling entries */ --- /sys/src/cmd/creepy/cons.c Tue May 22 18:19:27 2012 +++ /sys/src/cmd/creepy/cons.c Thu Jun 7 10:51:51 2012 @@ -393,6 +393,15 @@ sendul(fs->sweepc, 1); } +static void +cprof(int, char *argv[]) +{ + fs->profile = strcmp(argv[1], "on") == 0; + if(fs->profile) + consprint("profile on\n"); + else + consprint("profile off\n"); +} static void ccheck(int, char *argv[]) @@ -427,6 +436,7 @@ {"werr", crwerr, 2, "werr n"}, {"mark", cmark, 1, "mark"}, {"markmem", cmark, 1, "markmem"}, + {"prof", cprof, 2, "prof [on|off]"}, {"?", chelp, 1, "?"}, }; --- /sys/src/cmd/creepy/dbg.c Tue May 22 18:21:50 2012 +++ /sys/src/cmd/creepy/dbg.c Thu Jun 7 10:51:51 2012 @@ -180,7 +180,7 @@ if(b->type == DBfree) /* archer reads blocks without knowing their type */ b->type = b->d.type; if((b->type&~DBdirflag) != (b->d.type&~DBdirflag)) - error("type mismatch %s != %s", tname(b->type), tname(b->d.type)); + error("type mismatch: got %s not %s", tname(b->d.type), tname(b->type)); type = b->type & ~DBdirflag; switch(type){ case DBfree: --- /sys/src/cmd/creepy/dblk.c Tue May 22 18:21:53 2012 +++ /sys/src/cmd/creepy/dblk.c Thu Jun 7 10:51:51 2012 @@ -90,7 +90,6 @@ static int nr; long tot, n; uchar *p; - daddrt addr; if(write(0, &b->addr, sizeof b->addr) != sizeof b->addr) error("abread: write: %r"); @@ -98,7 +97,7 @@ for(tot = 0; tot < Dblksz; tot += n){ if(fs->swreaderr != 0 && ++nr > fs->swreaderr) warnerror("dbread: sw fault"); - n = pread(0, p+tot, Dblksz-tot, addr+tot); + n = read(0, p+tot, Dblksz-tot); if(n == 0) werrstr("abread: disk truncated"); if(n <= 0) @@ -181,6 +180,8 @@ Memblk *b; int i, n; + if(addr == 0) + error("null block"); dMprint("dbget %D\n", addr); b = mbload(addr); if(b->state == MBerr){ --- /sys/src/cmd/creepy/dk.h Tue May 22 18:21:56 2012 +++ /sys/src/cmd/creepy/dk.h Thu Jun 7 10:51:51 2012 @@ -494,6 +494,8 @@ List clean; /* hd: lru; tl: mru */ Channel *syncc; /* wakeup syncproc */ List out; /* dirty blocks waiting in write queue */ + QLock wlock; /* one fswrite at a time */ + Channel *syncrc; /* used by syncproc and syncworkers */ Lock nmblklk; uvlong nmblk; /* # of DBmem blocks */ --- /sys/src/cmd/creepy/fns.h Tue May 22 18:22:07 2012 +++ /sys/src/cmd/creepy/fns.h Thu Jun 7 10:51:51 2012 @@ -21,6 +21,7 @@ extern long conswrite(char *ubuf, long count); extern int daddrfmt(Fmt *fmt); extern Memblk* dbget(int type, daddrt addr); +extern Memblk* dbgetlocked(int type, daddrt addr, int isdisk); extern long dbread(Memblk *b); extern u64int dbsettag(daddrt addr, u64int e); extern long dbwrite(Memblk *b); @@ -36,6 +37,7 @@ extern Memblk* dfwalk(Memblk *d, char *name); extern long dfwattr(Memblk *f, char *name, char *val); extern Path* dropelem(Path **pp); +extern void dropproc(void*); extern void dumpfids(void); extern void dumplockstats(void); extern ulong embedattrsz(Memblk *f); @@ -68,13 +70,9 @@ extern void fswritetags(void); extern Fid* getfid(Cli* cli, uint no); extern void gmeta(Memblk *f, void *buf, ulong nbuf); -extern int ixcallfmt(Fmt *fmt); -extern uint ixpack(IXcall *f, uchar *ap, uint nap); -extern uint ixpackedsize(IXcall *f); extern char* ixstats(char *s, char *e, int clr, int verb); extern char* ixstats(char *s, char*, int, int); extern char* ixstats(char *s, char*, int, int); -extern uint ixunpack(uchar *ap, uint nap, IXcall *f); extern int leader(int gid, int lead); extern void listen9pix(char *addr, int noauth, char* (*cliworker)(void *arg, void **aux)); extern void lockstats(int on); @@ -147,6 +145,7 @@ extern void wstatint(Memblk *f, char *name, u64int v); extern int xcanqlock(QLock *q); extern int xcanwlock(RWLock *rw); +extern void xdftruncate(Memblk *f); extern void xmlinkhd(List *l, Memblk *b); extern void xmunlink(List *l, Memblk *b); extern void xqlock(QLock *q); --- /sys/src/cmd/creepy/fsys.c Tue May 22 18:22:10 2012 +++ /sys/src/cmd/creepy/fsys.c Thu Jun 7 10:51:51 2012 @@ -409,27 +409,37 @@ tmrproc(void*) { uint n; + Memblk *b; + Channel *c; + char *e; threadsetname("tmrproc"); errinit(Errstack); if(catcherror()) fatal("tmrproc: uncatched: %r"); n = 0; + c = chancreate(sizeof(char*), 0); for(;;){ sleep(1000); fstime(nsec()); /* with just one dirty block (/root) nothing has changed */ - if(fs->werr == nil) - if(fs->nmblk > 1 && (fs->nmblk>Mmaxdirty || (++n % Syncival) == 0)){ - xrlock(&fs->dquiescence); - dprint("tmr: sync %ulld blocks...\n", fs->nmblk); - if(catcherror()) - warn("couldn't sync: %r"); - else{ - fswrite(nil); - noerror(); + if(fs->werr == nil){ + b = fs->active; + if(b != nil && b->state == MBmem && + (fs->nmblk>Mmaxdirty || (++n % Syncival) == 0)){ + xrlock(&fs->dquiescence); + dZprint("tmr: sync %ulld blocks...\n", fs->nmblk); + if(catcherror()) + warn("couldn't sync: %r"); + else{ + fswrite(c); + e = recvp(c); + if(e != nil) + error(e); + noerror(); + } + xrunlock(&fs->dquiescence); } - xrunlock(&fs->dquiescence); } if(fs->mode != Worm && fs->archt != 0 && time(nil) > fs->archt){ fs->archt = 0; @@ -438,6 +448,30 @@ } } +static usize +freemem(void) +{ + int fd, n, ntoks; + char buf[128], *toks[16]; + usize pgsz, used, tot; + + fd = open("/dev/swap", OREAD); + if(fd < 0) + return 0; + n = read(fd, buf, sizeof buf - 1); + close(fd); + if(n <= 0) + return 0; + buf[n] = 0; + ntoks = getfields(buf, toks, nelem(toks), 1, " \t\n/"); + if(ntoks < 8) + return 0; + pgsz = strtoul(toks[2], 0, 0); + used = strtoul(toks[6], 0, 0); + tot = strtoul(toks[7], 0, 0); + return (tot - used) * pgsz; +} + static void fsinit(char *dev, int nblk) { @@ -445,6 +479,7 @@ Memblk *b, *e; uchar *c; uvlong nablk; + usize mem; /* this is an invariant that must hold for directories */ assert(Embedsz % Daddrsz == 0); @@ -469,10 +504,19 @@ fs->consrc = chancreate(sizeof(char*), 128); fs->conswc = chancreate(sizeof(char*), 0); fs->consec = chancreate(sizeof(char*), 0); + fs->syncrc = chancreate(sizeof(ulong), Nsyncprocs); fs->ifree = Dblk0addr; - nablk = Fsysmem / sizeof(Memblk); - if(nblk > 0 && nblk < nablk) + + mem = freemem() / 2; + if(mem == 0 || mem > Fsysmem) + mem = Fsysmem; + if(mem < Wormmem) + error("machine is low on memory"); + nablk = mem / sizeof(Memblk); + if(nblk > 0 && nablk > nblk) nablk = nblk; + dprint("using %ulld Mbytes\n", nablk * sizeof(Memblk) / MiB); + if(fs->fd < 0){ fs->limit = ~0; fs->ndblk = ~0; @@ -488,6 +532,7 @@ nablk = fs->ndblk; } } + p = malloc(nablk * sizeof fs->blk[0]); fs->blk = p; fs->mballoc.fixedsz = 1; --- /sys/src/cmd/creepy/ix.c Mon May 21 11:20:15 2012 +++ /sys/src/cmd/creepy/ix.c Thu Jun 7 10:51:51 2012 @@ -20,6 +20,9 @@ static int reply(Rpc*); +vlong ixcalltime[IXTmax]; +ulong ixncalls[IXTmax]; + static void (*ixcalls[])(Rpc*) = { [IXTversion] rversion, @@ -62,6 +65,25 @@ static int ixrreadhdrsz, ixrattrhdrsz; +int +rpcfmt(Fmt *fmt) +{ + Rpc *rpc; + extern char *npcallname[]; + + rpc = va_arg(fmt->args, Rpc*); + if(rpc == nil) + return fmtprint(fmt, ""); + if(rpc->t.type == 0) + return fmtprint(fmt, "Tnull"); + if(rpc->t.type >= Tversion && rpc->t.type < Tmax && npcallname[rpc->t.type]) + return fmtprint(fmt, "%s tag %ud", npcallname[rpc->t.type], rpc->t.tag); + if(rpc->t.type >= IXTversion && rpc->t.type < IXTmax && ixcallname[rpc->t.type]) + return fmtprint(fmt, "%s tag %ud", ixcallname[rpc->t.type], rpc->t.tag); + return fmtprint(fmt, "type=%d??? tag %ud", rpc->t.type, rpc->t.tag); +} + + char* ixstats(char *s, char *e, int clr, int verb) { @@ -72,13 +94,13 @@ if(verb == 0) return s; for(i = 0; i < nelem(ixcalls); i++) - if(ixcalls[i] != nil && ncalls[i] > 0){ + if(ixcalls[i] != nil && ixncalls[i] > 0){ s = seprint(s, e, "%-8s\t%5uld calls\t%11ulld µs\n", - callname[i], ncalls[i], - (calltime[i]/ncalls[i])/1000); + ixcallname[i], ixncalls[i], + (ixcalltime[i]/ixncalls[i])/1000); if(clr){ - ncalls[i] = 0; - calltime[i] = 0; + ixncalls[i] = 0; + ixcalltime[i] = 0; } } return s; @@ -481,8 +503,8 @@ return -1; } if(fs->profile) - calltime[rpc->xt.type] += nsec() - rpc->t0; - ncalls[rpc->xt.type]++; + ixcalltime[rpc->xt.type] += nsec() - rpc->t0; + ixncalls[rpc->xt.type]++; xqunlock(&cli->wlk); return p-buf; } @@ -491,7 +513,6 @@ rpcworkerix(void *v, void**aux) { Rpc *rpc, *rpc0; - Cli *cli; Channel *c; char err[128]; long nw; @@ -511,8 +532,7 @@ err[0] = 0; rpc = recvp(c); rpc0 = rpc; - cli = rpc->cli; - threadsetname("rpcworkerix %s chan %d", cli->addr, rpc0->chan); + threadsetname("rpcworkerix"); dPprint("%s started\n", threadgetname()); do{ --- /sys/src/cmd/creepy/mkfile Tue May 22 18:22:19 2012 +++ /sys/src/cmd/creepy/mkfile Thu Jun 7 10:51:52 2012 @@ -7,6 +7,7 @@ cmd\ rip\ arch\ + 9pixprof\ OFILES=\ dbg.$O\ @@ -20,7 +21,6 @@ write.$O\ IXOFILES=\ - ixcall.$O\ ix.$O\ 9p.$O\ cons.$O\ @@ -32,7 +32,6 @@ conf.h\ dk.h\ fns.h\ - ix.h\ net.h\ all.h\ @@ -48,6 +47,11 @@ $LD $LDFLAGS -o $target $prereq $O.arch: arch.$O $OFILES $IXOFILES $LIB $LD $LDFLAGS -o $target $prereq + + +$O.9pixprof: 9pix.$O $OFILES $IXOFILES $LIB + $LD $LDFLAGS -p -o $target $prereq + fns:V: c/f2p *.c >fns.h --- /sys/src/cmd/creepy/net.h Mon May 21 11:20:17 2012 +++ /sys/src/cmd/creepy/net.h Thu Jun 7 10:51:52 2012 @@ -109,7 +109,4 @@ #pragma varargck type "X" Fid* #pragma varargck type "R" Rpc* -extern vlong calltime[]; -extern ulong ncalls[]; -extern char *callname[]; extern Alloc fidalloc, rpcalloc, clialloc; --- /sys/src/cmd/creepy/rip.c Mon May 21 11:20:17 2012 +++ /sys/src/cmd/creepy/rip.c Thu Jun 7 10:51:52 2012 @@ -48,13 +48,13 @@ }ARGEND; if(argc != 1) usage(); - if(srv == nil || addr == nil) + if(srv == nil && addr == nil) srv = "rip"; dev = argv[0]; if(dbg['d']) dbg['Z'] = 1; - threadsetname("rip %s", dev); + threadsetname("rip"); outofmemoryexits(1); workerthreadcreate = proccreate; fmtinstall('H', mbfmt); --- /sys/src/cmd/creepy/sweep.c Tue May 22 18:20:35 2012 +++ /sys/src/cmd/creepy/sweep.c Thu Jun 7 10:51:52 2012 @@ -114,6 +114,11 @@ dbputlocked(b, isdisk); } +/* + * TODO: convert dfmark into a worker and, for diretories, spawn + * markers in parallel. + * markdentries is probably a good place to do it. + */ static void dfmark(daddrt addr, u64int e, int isdisk) { --- /sys/src/cmd/creepy/write.c Tue May 22 18:20:51 2012 +++ /sys/src/cmd/creepy/write.c Thu Jun 7 10:51:52 2012 @@ -169,6 +169,11 @@ * * TODO: If it's because of a disk-full, we should probably * ignore werr in fidremove(), and clear werr after a successful remove. + * + * If we order multiple writes before waiting for current ones to + * finish. The result is a train or dirty blocks going to disk which may + * grow until we cease ordering writes. + * So, we hold fs->wlock to get one fswrite at a time. */ void fswrite(Channel *c) @@ -180,17 +185,19 @@ if(fs->werr != nil) error("%s", fs->werr); + xqlock(&fs->wlock); dZprint("fswrite...\n"); t = opstart(&fs->opstat[Opwriteq], 0); t = opend(&fs->opstat[Opwriteq], t); t = opstart(&fs->opstat[Opwrite], t); xrlock(&fs->dquiescence); if(catcherror()){ + xqunlock(&fs->wlock); xrunlock(&fs->dquiescence); opend(&fs->opstat[Opwrite], t); - dZprint("fswrite: %r\n"); if(fs->werr == nil) fs->werr = smprint("%r"); + dZprint("fswrite: %r\n"); error(nil); } ainc(&fs->nwrite); @@ -231,10 +238,53 @@ noerror(); xrunlock(&fs->dquiescence); + xqunlock(&fs->wlock); opend(&fs->opstat[Opwrite], t); dZprint("fswrite: done\n"); } +static char* +syncworker(void *v, void **aux) +{ + Memblk *b; + + b = v; + threadsetname("syncworker"); + if(*aux == nil){ + errinit(Errstack); + *aux = v; /* make it not nil */ + } + if(catcherror()){ + warn("write %D: %r", b->addr); + if(b->type == DBsuper){ + if(b->wc != nil) + sendp(b->wc, smprint("%r")); + b->wc = nil; + mbput(b); + }else + mbset(b, MBerr); + sendul(fs->syncrc, 1); + return nil; + } + + dbwrite(b); + + noerror(); + if(b->type == DBsuper){ + if(b->wc != nil) + sendp(b->wc, nil); + b->wc = nil; + mbput(b); + }else{ + xqlock(&b->slk); + mbset(b, MBclean); + mlink(&fs->clean, b); + xqunlock(&b->slk); + } + sendul(fs->syncrc, 0); + return nil; +} + /* * Write blocks to disk, including copies for the super. */ @@ -243,48 +293,46 @@ { vlong t; Memblk *b; - int n; + int n, nn, nerrs, nprocs; threadsetname("syncproc"); errinit(Errstack); if(catcherror()) fatal("%s: uncatched: %r", threadgetname()); + for(;;){ recvul(fs->syncc); dZprint("sync...\n"); xrlock(&fs->dquiescence); t = opstart(&fs->opstat[Opsync], 0); - for(n = 0; (b = munlink(&fs->out, nil)) != nil; n++){ - if(catcherror()){ - warn("write %D: %r", b->addr); - if(b->type == DBsuper){ - if(b->wc != nil) - sendp(b->wc, smprint("%r")); - b->wc = nil; - mbput(b); - }else - mbset(b, MBerr); - xrunlock(&fs->dquiescence); - continue; - } - - dbwrite(b); - noerror(); - if(b->type == DBsuper){ - if(b->wc != nil) - sendp(b->wc, nil); - b->wc = nil; - mbput(b); - }else{ - xqlock(&b->slk); - mbset(b, MBclean); - mlink(&fs->clean, b); - xqunlock(&b->slk); + nerrs = 0; + n = nn = 0; + do{ + nprocs = 0; + while((b = munlink(&fs->out, nil)) != nil && b->type != DBsuper){ + if(nprocs == Nsyncprocs){ + nerrs += recvul(fs->syncrc); + nprocs--; + } + nn++; + getworker(syncworker, b, nil); + nprocs++; } - } + for(; nprocs > 0; nprocs--) + nerrs += recvul(fs->syncrc); + if(b != nil){ /* XXX: don't write if nerrs? */ + nn++; + dZprint("sync: %d blocks, %d errors\n", + nn, nerrs); + getworker(syncworker, b, nil); + nerrs += recvul(fs->syncrc); + } + n += nn; + }while(b != nil); + opend(&fs->opstat[Opsync], t); - dZprint("sync: wrote %d blocks\n", n); + dZprint("sync: total %d blocks, %d errors\n", n, nerrs); xrunlock(&fs->dquiescence); } }