# HG changeset patch # User Francisco J Ballesteros # Date 1332270844 -3600 # Node ID bc7aa6acf2c206ac3259480f8dcf83284759ea48 # Parent 0c7cafcb782cc440054733aff4126200d0ea0b2f creepy: alpha version. It passed all the (silly) tests I made on it. Not yet ready for use, but I'm going to use it to host my home and trigger more bugs. R=nixiedev CC=nix-dev http://codereview.appspot.com/5847048 diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/9pix.c --- a/sys/src/cmd/creepy/9pix.c Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/9pix.c Tue Mar 20 20:14:04 2012 +0100 @@ -1,23 +1,12 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "ix.h" -#include "net.h" -#include "fns.h" +#include "all.h" static RWLock fidhashlk; static Fid *fidshd, *fidstl; static Fid *fidhash[Fidhashsz]; static uint fidgen; +int noauth; + Alloc fidalloc = { .elsz = sizeof(Fid), @@ -135,6 +124,22 @@ dprint("meltfids: %d fids advanced\n", n); } +void +countfidrefs(void) +{ + Fid *fid; + Path *p; + int i; + + xrwlock(&fidhashlk, Rd); + for(fid = fidshd; fid != nil; fid = fid->next){ + p = fid->p; + for(i = 0; i < p->nf; i++) + mbcountref(p->f[i]); + } + xrwunlock(&fidhashlk, Rd); +} + Rpc* newrpc(void) { @@ -255,6 +260,7 @@ cli->cfd = cfd; cli->addr = addr; cli->ref = 1; + cli->uid = -1; xqlock(&clientslk); cli->next = clients; @@ -285,9 +291,21 @@ } void -fidattach(Fid *fid, char *aname, char *uname) +consprintclients(void) { - Path *p; + Cli *c; + + xqlock(&clientslk); + for(c = clients; c != nil; c = c->next) + consprint("%s!%s\n", c->addr, usrname(c->uid)); + xqunlock(&clientslk); +} + +void +setfiduid(Fid *fid, char *uname) +{ + if(uname[0] == 0) + error("null uid"); fid->uid = usrid(uname); @@ -303,8 +321,16 @@ if(fid->uid < 0){ fprint(2, "%s: unknown user '%s'. using 'none'\n", argv0, uname); - fid->uid = 1; + fid->uid = usrid("none"); } +} + +void +fidattach(Fid *fid, char *aname, char *uname) +{ + Path *p; + + setfiduid(fid, uname); p = newpath(fs->root); fid->p = p; if(strcmp(aname, "active") == 0 || strcmp(aname, "main/active") == 0){ @@ -747,10 +773,8 @@ ulong tot, nr; d = fid->p->f[fid->p->nf-1]; - for(tot = 0; tot+2 < ndata; tot += nr){ + for(tot = 0; tot+2 < ndata && fid->lidx < d->d.ndents; tot += nr){ f = dfchild(d, fid->lidx); - if(f == nil) - break; nr = pack(f, data+tot, ndata-tot); mbput(f); if(nr <= 2) @@ -1034,7 +1058,7 @@ rwunlock(f, Rd); error(nil); } - for(i = 0; i < f->d.length/Daddrsz; i++) + for(i = 0; i < f->d.ndents; i++) mbput(dfchild(f, i)); noerror(); rwunlock(f, Rd); @@ -1142,6 +1166,9 @@ case 'n': addr = EARGF(usage()); break; + case 'a': + noauth = 1; + break; default: if(ARGC() >= 'A' && ARGC() <= 'Z' || ARGC() == '9'){ dbg['d'] = 1; @@ -1176,6 +1203,7 @@ listen9pix(addr, cliworker9p); consinit(); + proccreate(fssyncproc, nil, Stack); noerror(); threadexits(nil); } diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/conf.h --- a/sys/src/cmd/creepy/conf.h Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/conf.h Tue Mar 20 20:14:04 2012 +0100 @@ -8,15 +8,6 @@ MiB = KiB * 1024UL, GiB = MiB * 1024UL, -#ifdef TESTING - Incr = 2, - Fsysmem = 200*KiB, /* size for in-memory block array */ - - /* disk parameters; don't change */ - Dblksz = 512UL, /* disk block size */ - Ndptr = 2, /* # of direct data pointers */ - Niptr = 2, /* # of indirect data pointers */ -#else Incr = 16, Fsysmem = 2*GiB, /* size for in-memory block array */ @@ -24,7 +15,8 @@ Dblksz = 16*KiB, /* disk block size */ Ndptr = 8, /* # of direct data pointers */ Niptr = 4, /* # of indirect data pointers */ -#endif + + Syncival = 60, /* desired sync intervals (s) */ Mmaxdirtypcent = 50, /* Max % of blocks dirty in mem */ Mminfree = 50, /* # blocks when low on mem blocks */ @@ -37,8 +29,8 @@ * Caution: Errstack also limits the max tree depth, * because of recursive routines (in the worst case). */ - Stack = 32*KiB, /* stack size for threads */ - Errstack = 64, /* max # of nested error labels */ + Stack = 64*KiB, /* stack size for threads */ + Errstack = 128, /* max # of nested error labels */ Fhashsz = 7919, /* size of file hash (plan9 has 35454 files). */ Fidhashsz = 97, /* size of the fid hash size */ Uhashsz = 97, @@ -55,6 +47,5 @@ Unamesz = 20, Statsbufsz = 1024, - Syncival = 60 * 1000, /* desired sync intervals (ms) */ }; diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/dk.h --- a/sys/src/cmd/creepy/dk.h Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/dk.h Tue Mar 20 20:14:04 2012 +0100 @@ -4,6 +4,7 @@ typedef struct Dattrblk Dattrblk; typedef struct Dfileblk Dfileblk; typedef struct Dsuperblk Dsuperblk; +typedef struct Dsuperdata Dsuperdata; typedef union Diskblk Diskblk; typedef struct Diskblkhdr Diskblkhdr; typedef struct Memblk Memblk; @@ -235,10 +236,15 @@ * ... * (/ and /active are only memory and never on disk, parts * under /active that are on disk are shared with entries in /archive) + * + * It contains two copies of the information, Both should be identical. + * If there are errors while writing this block, the one with the + * oldest epoch should be ok. */ -struct Dsuperblk +struct Dsuperdata { u64int magic; /* MAGIC */ + u64int epoch; daddrt free; /* first free block on list */ daddrt eaddr; /* end of the assigned disk portion */ daddrt root; /* address of /archive in disk */ @@ -255,6 +261,15 @@ u64int dptrperblk; /* only for checking */ }; +struct Dsuperblk +{ + union{ + Dsuperdata; + uchar align[Dblksz/2]; + }; + Dsuperdata dup; +}; + enum { /* addresses for ctl files and / have this bit set, and are never @@ -374,7 +389,6 @@ Lock dirtylk; int dirty; /* must be written */ int frozen; /* is frozen */ - int aflag; /* part of the "/archive" file? */ int loading; /* block is being read */ int changed; /* for freerefs/writerefs */ QLock newlk; /* only to wait on DBnew blocks */ @@ -438,7 +452,7 @@ RWLock quiescence; /* any activity rlocks() this */ QLock policy; /* fspolicy */ - uchar *chk; /* for fscheck() */ + uchar *mchk, *dchk; /* for fscheck() */ uvlong wtime; /* time for last fswrite */ }; diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/fblk.c --- a/sys/src/cmd/creepy/fblk.c Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/fblk.c Tue Mar 20 20:14:04 2012 +0100 @@ -1,16 +1,4 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "ix.h" -#include "net.h" -#include "fns.h" +#include "all.h" /* * File blocks. @@ -56,7 +44,7 @@ /* for dfblk only */ static Memblk* -getmelted(uint isdir, int isarch, uint type, daddrt *addrp, int *chg) +getmelted(uint isdir, uint type, daddrt *addrp, int *chg) { Memblk *b, *nb; @@ -65,14 +53,11 @@ b = dballoc(type); *addrp = b->addr; *chg = 1; - b->aflag = isarch; return b; } b = dbget(type, *addrp); nb = nil; - if(isarch) - b->frozen = 0; /* /archive always melted */ if(!b->frozen) return b; if(catcherror()){ @@ -103,20 +88,15 @@ * Read-ahead is not considered here. The file only records * the last accessed block number, to help the caller do RA. * - * Blocks added to "/archive" are flagged with aflag, as an aid - * to write them even though "/archive" is never frozen. */ static Memblk* dfblk(Memblk *f, ulong bno, int mkit) { ulong prev, nblks; - int i, idx, nindir, type, isdir, isarch, chg; + int i, idx, nindir, type, isdir, chg; Memblk *b, *pb; daddrt *addrp; - isarch = f == fs->archive; - if(isarch) - f->frozen = 0; if(mkit) ismelted(f); isdir = (f->d.mode&DMDIR); @@ -138,12 +118,11 @@ */ if(bno < nelem(f->d.dptr)){ if(mkit) - b = getmelted(isdir, isarch, DBdata, &f->d.dptr[bno], &chg); + b = getmelted(isdir, DBdata, &f->d.dptr[bno], &chg); else b = dbget(DBdata, f->d.dptr[bno]); if(chg) changed(f); - b->aflag = isarch; return b; } bno -= nelem(f->d.dptr); @@ -170,10 +149,9 @@ addrp = &f->d.iptr[i]; if(mkit) - b = getmelted(isdir, isarch, type, addrp, &chg); + b = getmelted(isdir, type, addrp, &chg); else b = dbget(type, *addrp); - b->aflag = isarch; if(chg) changed(f); pb = b; @@ -204,11 +182,9 @@ }else{ assert(type >= DBdata); if(mkit) - b = getmelted(isdir, isarch, type, addrp, &chg); + b = getmelted(isdir, type, addrp, &chg); else b = dbget(type, *addrp); - b->aflag = isarch; - if(chg) changed(pb); addrp = &b->d.ptr[idx]; @@ -582,7 +558,7 @@ /* * Return the last version for *fp, wlocked, be it frozen or melted. */ -static void +void followmelted(Memblk **fp, int iswr) { Memblk *f; @@ -854,8 +830,8 @@ noerror(); rwunlock(f, Wr); if(!catcherror()){ - n = dfreclaim(f); - dprint("dfreclaim d%#ullx: %lld blks\n", f->addr, n); + n = dfput(f); + dprint("dfput d%#ullx: %lld blks\n", f->addr, n); noerror(); } mbput(f); @@ -981,7 +957,7 @@ child = dfchild; if(!isdisk) child = mfchild; - for(i = 0; i < f->d.length/Daddrsz; i++){ + for(i = 0; i < f->d.ndents; i++){ b = child(f, i); if(b == nil) continue; @@ -1051,12 +1027,12 @@ int old; idx = addr/Dblksz; - old = fs->chk[idx]; - if(fs->chk[idx] == 0xFE) + old = fs->dchk[idx]; + if(fs->dchk[idx] == 0xFE) fprint(2, "fscheck: d%#010ullx: too many refs, ignoring some\n", addr); else - fs->chk[idx]++; + fs->dchk[idx]++; return old; } @@ -1074,12 +1050,12 @@ long i; i = addr/Dblksz; - if(fs->chk[i] != 0 && fs->chk[i] <= 0xFE) + if(fs->dchk[i] != 0 && fs->dchk[i] <= 0xFE) fprint(2, "fscheck: d%#010ullx: free block in use\n", addr); - else if(fs->chk[i] == 0xFF) + else if(fs->dchk[i] == 0xFF) fprint(2, "fscheck: d%#010ullx: double free\n", addr); else - fs->chk[i] = 0xFF; + fs->dchk[i] = 0xFF; } void @@ -1140,8 +1116,6 @@ if(f->d.mode&DMDIR) for(i = 0; i < f->d.length/Daddrsz; i++){ b = dfchild(f, i); - if(b == nil) - continue; if(catcherror()){ fprint(2, "fscheck: '%s' d%#010ullx:" " child[%d]: %r\n", @@ -1172,14 +1146,14 @@ * to look, besides dbdup and dfchdentry. */ int -dfreclaim(Memblk *f) +dfput(Memblk *f) { int i; Memblk *b; long tot; isfile(f); - dKprint("dfreclaim %H\n", f); + dKprint("dfput %H\n", f); /* * Remove children if it's the last disk ref before we drop data blocks. * No new disk refs may be added, so there's no race here. @@ -1191,12 +1165,10 @@ rwunlock(f, Wr); error(nil); } - for(i = 0; i < f->d.length/Daddrsz; i++){ + for(i = 0; i < f->d.ndents; i++){ b = dfchild(f, i); - if(b == nil) - continue; if(!catcherror()){ - tot += dfreclaim(b); + tot += dfput(b); noerror(); } mbput(b); diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/fns.h --- a/sys/src/cmd/creepy/fns.h Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/fns.h Tue Mar 20 20:14:04 2012 +0100 @@ -11,8 +11,12 @@ extern Path* clonepath(Path *p); extern void consinit(void); extern void consprint(char *fmt, ...); +extern void consprintclients(void); extern long consread(char *buf, long count); extern long conswrite(char *ubuf, long count); +extern void countfidrefs(void); +extern void countfidrefs(void); +extern void countfidrefs(void); extern Memblk* dballoc(uint type); extern Memblk* dbdup(Memblk *b); extern Memblk* dbget(uint type, daddrt addr); @@ -38,9 +42,9 @@ extern void dflink(Memblk *d, Memblk *f); extern Path* dfmelt(Path **pp, int nth); extern ulong dfpread(Memblk *f, void *a, ulong count, uvlong off); +extern int dfput(Memblk *f); extern ulong dfpwrite(Memblk *f, void *a, ulong count, uvlong *off); extern long dfrattr(Memblk *f, char *name, void *val, long count); -extern int dfreclaim(Memblk *f); extern void dfremove(Memblk *p, Memblk *f); extern Blksl dfslice(Memblk *f, ulong len, uvlong off, int iswr); extern void dfused(Path *p); @@ -61,8 +65,10 @@ extern void fidremove(Fid *fid); extern void fidwalk(Fid *fid, char *wname); extern long fidwrite(Fid *fid, void *data, ulong count, uvlong *offset); +extern void followmelted(Memblk **fp, int iswr); extern void freerpc(Rpc *rpc); extern int fscheck(void); +extern uvlong fsdiskfree(void); extern void fsdump(int full, int disktoo); extern void fsfmt(char *dev); extern int fsfull(void); @@ -72,6 +78,7 @@ extern void fspolicy(void); extern int fsreclaim(void); extern void fssync(void); +extern void fssyncproc(void*); extern Fid* getfid(void* clino, int no); extern void gmeta(Memblk *f, void *buf, ulong nbuf); extern void isfile(Memblk *f); @@ -88,6 +95,7 @@ extern int leader(int gid, int lead); extern void lockstats(int on); extern Memblk* mballoc(daddrt addr); +extern int mbcountref(Memblk *b); extern int mbfmt(Fmt *fmt); extern Memblk* mbget(int type, daddrt addr, int mkit); extern Memblk* mbhash(Memblk *b); @@ -128,6 +136,7 @@ extern void rwusers(Memblk*); extern void rwusers(Memblk*); extern int setdebug(void); +extern void setfiduid(Fid *fid, char *uname); extern char* tname(int t); extern char* updatestats(int clr); extern int usrfmt(Fmt *fmt); diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/fscmd.c --- a/sys/src/cmd/creepy/fscmd.c Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/fscmd.c Tue Mar 20 20:14:04 2012 +0100 @@ -1,16 +1,4 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "ix.h" -#include "net.h" -#include "fns.h" +#include "all.h" /* * HUGE warning: @@ -76,6 +64,11 @@ return s; } +void +countfidrefs(void) +{ +} + /* * Walks elems starting at f. * Ok if nelems is 0. @@ -346,7 +339,11 @@ static void fsdbg(int, char *argv[]) { - dbg['D'] = atoi(argv[1]); + char *s; + + memset(dbg, 0, sizeof dbg); + for(s = argv[1]; *s; s++) + dbg['D'] = dbg[*s] = 1; } static void @@ -394,7 +391,8 @@ static void fschk(int, char**) { - fscheck(); + if(fscheck() != 0) + error("check failed"); } static void @@ -410,6 +408,12 @@ } static void +fspol(int, char**) +{ + fspolicy(); +} + +static void usage(void) { fprint(2, "usage: %s [-DFLAGS] [-dv] [-f disk] cmd...\n", argv0); @@ -436,6 +440,7 @@ {"check", fschk, 1, "check"}, {"rerr", fserr, 2, "rerr!n"}, {"werr", fserr, 2, "werr!n"}, + {"pol", fspol, 1, "pol"}, }; void @@ -466,12 +471,12 @@ fmtinstall('H', mbfmt); fmtinstall('M', dirmodefmt); errinit(Errstack); - if(catcherror()) - fatal("error: %r"); + if(catcherror()){ + fprint(2, "cmd failed: %r\n"); + threadexitsall("failed"); + } fsopen(dev); for(i = 0; i < argc; i++){ - if(catcherror()) - fatal("cmd %s: %r", argv[i]); if(verb>1) fsdump(0, Mem); print("%% %s\n", argv[i]); @@ -483,10 +488,8 @@ fprint(2, "usage: %s\n", cmds[j].usage); else cmds[j].f(nargs, args); - fspolicy(); break; } - noerror(); if(j == nelem(cmds)){ fprint(2, "no such command\n"); for(j = 0; j < nelem(cmds); j++) @@ -497,6 +500,6 @@ if(verb>1) fsdump(0, Mem); noerror(); - exits(nil); + threadexitsall(nil); } diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/fsfmt.c --- a/sys/src/cmd/creepy/fsfmt.c Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/fsfmt.c Tue Mar 20 20:14:04 2012 +0100 @@ -1,16 +1,4 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "ix.h" -#include "net.h" -#include "fns.h" +#include "all.h" int usrid(char*) @@ -58,6 +46,11 @@ return s; } +void +countfidrefs(void) +{ +} + static void usage(void) { diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/fsys.c --- a/sys/src/cmd/creepy/fsys.c Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/fsys.c Tue Mar 20 20:14:04 2012 +0100 @@ -1,16 +1,4 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "ix.h" -#include "net.h" -#include "fns.h" +#include "all.h" /* * All the code assumes outofmemoryexits = 1. @@ -48,7 +36,7 @@ xrwunlock(&fs->quiescence, Rd); } -static uvlong +uvlong fsdiskfree(void) { uvlong nfree; @@ -188,6 +176,66 @@ debug(); } +static int +counted(Memblk *b) +{ + uint i; + + if(b == nil) + return 0; + i = b - fs->blk; + if(b < fs->blk || b >= fs->blk + fs->nablk) + fatal("mbcountref: m%#p not in global array", b); + if(fs->mchk[i] == 0xFE && b->ref < (int)0xFE){ + fprint(2,"fscheck: m%#p: found >%ud != ref %ud\n%H\n", + b, fs->mchk[i], b->ref, b); + return 1; + }else if(fs->mchk[i] < 0xFE && b->ref != fs->mchk[i]){ + fprint(2,"fscheck: m%#p: found %ud != ref %ud\n%H\n", + b, fs->mchk[i], b->ref, b); + return 1; + } + return 0; +} + +static long +fscheckrefs(void) +{ + long nfails; + int i; + Memblk *b; + + nfails = 0; + mbcountref(fs->super); + mbcountref(fs->root); + mbcountref(fs->active); + mbcountref(fs->archive); + mbcountref(fs->cons); + mbcountref(fs->stats); + mbcountref(fs->fzsuper); + countfidrefs(); + for(i = 0; i < nelem(fs->fhash); i++) + for(b = fs->fhash[i].b; b != nil; b = b->next) + mbcountref(b); + + for(i = 0; i < nelem(fs->fhash); i++) + for(b = fs->fhash[i].b; b != nil; b = b->next) + nfails += counted(b); + nfails += counted(fs->super); + nfails += counted(fs->root); + nfails += counted(fs->active); + nfails += counted(fs->archive); + nfails += counted(fs->cons); + nfails += counted(fs->stats); + nfails += counted(fs->fzsuper); + + if(nfails > 0 && dbg['d']){ + dprint("fscheckrefs: %ld fails. sleeping\n", nfails); + while(1)sleep(5000); + } + return nfails; +} + /* * Failed checks are reported but not fixed (but for leaked blocks). * The user is expected to format the partition and restore contents from venti. @@ -203,10 +251,13 @@ xqlock(&fs->fzlk); xrwlock(&fs->quiescence, Wr); nfails = 0; - if(fs->chk == nil) - fs->chk = mallocz(fs->ndblk, 1); - else - memset(fs->chk, 0, fs->ndblk); + if(fs->dchk == nil){ + fs->dchk = mallocz(fs->ndblk, 1); + fs->mchk = mallocz(fs->nablk, 1); + }else{ + memset(fs->dchk, 0, fs->ndblk); + memset(fs->mchk, 0, fs->nablk); + } if(catcherror()){ xrwunlock(&fs->quiescence, Wr); xqunlock(&fs->fzlk); @@ -215,7 +266,10 @@ return nfails; } - fprint(2, "%s: checking %s...\n", argv0, fs->dev); + fprint(2, "%s: checking '%s'...\n", argv0, fs->dev); + dprint("mem checks...\n"); + nfails += fscheckrefs(); + dprint("disk checks...\n"); nfails += dfcountrefs(fs->root); dprint("countfree...\n"); dfcountfree(); @@ -223,7 +277,7 @@ dprint("checks...\n"); for(addr = 0; addr < fs->super->d.eaddr; addr += Dblksz){ i = addr/Dblksz; - if(fs->chk[i] == 0){ + if(fs->dchk[i] == 0){ fprint(2, "fscheck: d%#010ullx: leak\n", addr); if(!catcherror()){ dbsetref(addr, fs->super->d.free); @@ -235,24 +289,28 @@ } continue; } - if(fs->chk[i] == 0xFF) + if(fs->dchk[i] == 0xFF) continue; n = dbgetref(addr); - if(fs->chk[i] == 0xFE && n < (daddrt)0xFE){ + if(fs->dchk[i] == 0xFE && n < (daddrt)0xFE){ fprint(2, "fscheck: d%#010ullx: found >%ud != ref %ulld\n", - addr, fs->chk[i], n); + addr, fs->dchk[i], n); nfails++; } - if(fs->chk[i] < 0xFE && n != fs->chk[i]){ + if(fs->dchk[i] < 0xFE && n != fs->dchk[i]){ fprint(2, "fscheck: d%#010ullx: found %ud != ref %ulld\n", - addr, fs->chk[i], n); + addr, fs->dchk[i], n); nfails++; } } xrwunlock(&fs->quiescence, Wr); xqunlock(&fs->fzlk); noerror(); - fprint(2, "%s: %s check complete\n", argv0, fs->dev); + if(nfails > 0 && dbg['d']){ + dprint("fscheck: %ld fails. sleeping\n", nfails); + while(1)sleep(5000); + } + fprint(2, "%s: '%s' checks %s\n", argv0, fs->dev, nfails?"fail":"pass"); return nfails; } @@ -315,6 +373,7 @@ readsuper(void) { Memblk *super; + Dsuperdata *d1, *d2; if(catcherror()){ error("not a creepy disk: %r"); @@ -324,6 +383,13 @@ super = fs->super; if(super->d.magic != MAGIC) error("bad magic number"); + d1 = &fs->super->d.Dsuperdata; + d2 = &fs->super->d.dup; + if(memcmp(d1, d2, sizeof(Dsuperdata)) != 0){ + fprint(2, "%s: partially written superblock, using old.\n", argv0); + if(fs->super->d.dup.epoch < fs->super->d.epoch) + fs->super->d.Dsuperdata = fs->super->d.dup; + } if(super->d.dblksz != Dblksz) error("bad Dblksz"); if(super->d.nblkgrpsz != Nblkgrpsz) @@ -340,11 +406,43 @@ error("bad Embedsz"); if(super->d.dptrperblk != Dptrperblk) error("bad Dptrperblk"); + noerror(); return super; } /* + * Ensure /archive is melted, releasing the old one after melting + * it when frozen. + */ +static void +meltedarchive(void) +{ + Memblk *arch, *oarch; + daddrt addr; + + addr = fs->archive->addr; + followmelted(&fs->archive, Wr); + if(catcherror()){ + rwunlock(fs->archive, Wr); + error(nil); + } + if(fs->archive->frozen != 0){ + oarch = fs->archive; + arch = dbdup(fs->archive); + rwlock(arch, Wr); + rwunlock(oarch, Wr); + dfchdentry(fs->root, addr, arch->addr, Dontmk); + dfput(oarch); + mbput(oarch); + fs->archive = arch; + fs->super->d.root = fs->archive->addr; + changed(fs->super); + } + noerror(); +} + +/* * Freeze the file tree, keeping active as a new melted file * that refers to frozen children now in the archive. * returns the just frozen tree or nil @@ -385,14 +483,15 @@ } oa = fs->active; - arch = fs->archive; rwlock(fs->root, Wr); - rwlock(oa, Wr); - rwlock(arch, Wr); + /* * move active into /archive/. */ + meltedarchive(); + arch = fs->archive; + rwlock(oa, Wr); seprint(name, name+sizeof(name), "%ulld", oa->d.mtime); wname(oa, name, strlen(name)+1); dflink(arch, oa); @@ -401,10 +500,11 @@ */ oa->d.mtime = t0; oa->d.atime = t0; - rwunlock(oa, Wr); /* race */ + rwunlock(oa, Wr); changed(oa); dffreeze(oa); rwunlock(arch, Wr); + dffreeze(arch); /* 2. Freeze the on-disk reference counters * and the state of the super-block. @@ -462,7 +562,7 @@ static int mustwrite(Memblk *b) { - return b->frozen != 0 || b == fs->archive || b->aflag != 0; + return b->frozen != 0; } /* @@ -497,6 +597,8 @@ if(canqlock(&fs->fzlk)) fatal("writezsuper: lock"); assert(fs->fzsuper != nil); + fs->fzsuper->d.epoch = nsec(); + fs->fzsuper->d.dup = fs->fzsuper->d.Dsuperdata; dbwrite(fs->fzsuper); dprint("writezsuper: %H\n", fs->fzsuper); mbput(fs->fzsuper); @@ -650,7 +752,6 @@ rwlock(fs->root, Wr); fs->active = dfcreate(fs->root, "active", uid, DMDIR|0775); fs->archive = dfcreate(fs->root, "archive", uid, DMDIR|0555); - fs->archive->aflag = 1; rwunlock(fs->root, Wr); super->d.root = fs->archive->addr; fssync(); @@ -659,6 +760,20 @@ } /* + * If there are dirty blocks, call the policy once per Syncival. + */ +void +fssyncproc(void*) +{ + threadsetname("syncer"); + errinit(Errstack); + for(;;){ + sleep(Syncival*1000); + fspolicy(); + } +} + +/* * One process per file system, so consume all the memory * for the cache. * To open more file systems, use more processes! @@ -679,12 +794,13 @@ xqlock(&fs->fzlk); fs->root = dfcreate(nil, "", uid, DMDIR|0555); arch = dbget(DBfile, fs->super->d.root); - arch->aflag = 1; fs->archive = arch; rwlock(fs->root, Wr); rwlock(arch, Wr); last = nil; - for(i = 0; (c = dfchild(arch, i)) != nil; i++){ + + for(i = 0; i < arch->d.ndents; i++){ + c = dfchild(arch, i); if(last == nil || last->d.mtime < c->d.mtime){ mbput(last); last = c; @@ -855,32 +971,42 @@ Memblk *arch, *c, *victim; int i; daddrt addr; - Blksl sl; long n, tot; xqlock(&fs->fzlk); + rwlock(fs->root, Wr); + if(catcherror()){ + rwunlock(fs->root, Wr); + xqunlock(&fs->fzlk); + error(nil); + } fprint(2, "%s: %ulld free: reclaiming...\n", argv0, fsdiskfree()); if(fs->fzsuper != nil){ /* * we did freeze/reclaim and are still writing, can't reclaim now. */ + noerror(); + rwunlock(fs->root, Wr); xqunlock(&fs->fzlk); fprint(2, "%s: writing, skip reclaim\n", argv0); return 0; } - + meltedarchive(); arch = fs->archive; - rwlock(arch, Wr); if(catcherror()){ rwunlock(arch, Wr); - xqunlock(&fs->fzlk); error(nil); } tot = 0; for(;;){ dprint("fsreclaim: reclaiming\n"); victim = nil; - for(i = 0; (c = dfchild(arch, i)) != nil; i++){ + if(arch->d.ndents < 2){ + dprint("nothing to reclaim\n"); + break; + } + for(i = 0; i < arch->d.ndents; i++){ + c = dfchild(arch, i); if(victim == nil) victim = c; else if(victim->d.mtime > c->d.mtime){ @@ -890,38 +1016,15 @@ mbput(c); } - if(i < 2){ - mbput(victim); - dprint("nothing to reclaim\n"); - break; - } fprint(2, "%s: reclaiming /archive/%s\n", argv0, victim->mf->name); dprint("victim is %H\n", victim); - addr = dfchdentry(arch, victim->addr, 0, Dontmk); - - /* - * Write the new /archive without the file reclaimed, in - * case we fail while reclaiming. - */ - sl = dfslice(arch, sizeof(u64int), addr, Rd); - if(sl.b != nil && sl.b != arch){ - munlink(&fs->mdirty, sl.b, 0); - if(!catcherror()){ - dbwrite(sl.b); - noerror(); - } - } - mbput(sl.b); - changed(arch); - munlink(&fs->mdirty, arch, 0); - dbwrite(arch); - - n = dfreclaim(victim); + addr = dfchdentry(arch, victim->addr, 0, Mkit); + fs->super->d.root = arch->addr; + assert(dbgetref(victim->addr) == 1); + n = dfput(victim); mbput(victim); - fs->super->d.root = arch->addr; - dprint("fsreclaim: %uld file%s reclaimed\n", n, n?"s":""); tot += n; @@ -937,7 +1040,9 @@ }else fprint(2, "%s: %uld file%s reclaimed %ulld blocks free\n", argv0, tot, tot?"s":"", fsdiskfree()); + noerror(); rwunlock(arch, Wr); + rwunlock(fs->root, Wr); xqunlock(&fs->fzlk); noerror(); return tot; @@ -956,41 +1061,28 @@ /* * Policy for memory and and disk block reclaiming. - * Should be called from time to time to guarantee that there are free blocks. + * Called from the sync proc from time to time and also AFTER each RPC. */ void fspolicy(void) { int lomem, lodisk, hidirty, longago; - /* - * XXX: This will call fswrite() while blocking everyone calling - * fspolicy(), including all rpcs. - * - * That's done so now because the sizes used for testing are a joke, - * so that a single rpc may fill the disk even while another is already - * running the policy!, despite water marks! - * - * Once testing is complete, we should insist on running the policy - * (qlock it) only if we are really low on resources, otherwise, we - * should canqlock or defer it for later (because the most likely - * reason we can't qlock it is that it's already running and perhaps - * writing the frozen fs to disk). - * - * If we forget to make that change, writes will become - * synchronous and that should be considered as a BUG. - * - */ - xqlock(&fs->policy); + if(!canqlock(&fs->policy)){ + if(fsmemfree() > Mzerofree && fsdiskfree() > Dzerofree) + return; /* not in a hurry, let's others do it. */ + qlock(&fs->policy); + } if(catcherror()){ - xqunlock(&fs->policy); - fatal("fspolicy: %r"); /* should just print and return */ + qunlock(&fs->policy); + fprint(2, "%s: fspolicy: %r", argv0); + return; } lomem = fsmemfree() < Mminfree; lodisk = fsdiskfree() < Dminfree; hidirty = fsdirtypcent() > Mmaxdirtypcent; - longago = (nsec() - fs->wtime)/1000000UL > Syncival; + longago = (nsec() - fs->wtime)/NSPERSEC > Syncival; /* Ideal sequence for [lomem lodisk hidirty] might be: * 111: lru sync reclaim+sync lru @@ -1018,11 +1110,12 @@ } if(lodisk) fsreclaim(); - if(lodisk || hidirty || longago) + + if(lodisk || hidirty || (longago && fs->mdirty.n != 0)) fssync(); if(lomem && hidirty) fslru(); + noerror(); qunlock(&fs->policy); - noerror(); } diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/mblk.c --- a/sys/src/cmd/creepy/mblk.c Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/mblk.c Tue Mar 20 20:14:04 2012 +0100 @@ -1,16 +1,4 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "ix.h" -#include "net.h" -#include "fns.h" +#include "all.h" /* * memory blocks. @@ -208,7 +196,7 @@ void ismelted(Memblk *b) { - if(b != fs->archive && b->aflag == 0 && b->frozen) + if(b->frozen) fatal("frozen at pc %#p", getcallerpc(&b)); } @@ -426,7 +414,7 @@ xqlock(&fs->fhash[hv]); for(h = &fs->fhash[hv].b; *h != nil; h = &(*h)->next) if((*h)->addr == b->addr){ - fprint(2, "mbhash: dup blocks\n"); + fprint(2, "mbhash: dup blocks:\n"); fprint(2, "b=> %H\n*h=> %H\n", b, *h); fatal("mbhash: dup"); } @@ -498,7 +486,7 @@ b->addr = 0; b->type = DBfree; b->d.tag = DBfree; - b->frozen = b->dirty = b->aflag = b->loading = b->changed = 0; + b->frozen = b->dirty = b->loading = b->changed = 0; xqlock(fs); fs->nmused--; @@ -601,3 +589,28 @@ mbfree(b); } +/* + * for fscheck + */ +int +mbcountref(Memblk *b) +{ + int i, old; + + if(b == nil) + return 0; + if(b < fs->blk || b >= fs->blk + fs->nablk) + fatal("mbcountref: m%#p not in global array", b); + i = b - fs->blk; + old = fs->mchk[i]; + if(fs->mchk[i] == 0xFE) + fprint(2, "fscheck: m%#p: too many refs, ignoring some\n", + b); + else + fs->mchk[i]++; + + if(old == 0 && b->type == DBfile) + mbcountref(b->mf->melted); + return old; +} + diff -r 0c7cafcb782c -r bc7aa6acf2c2 sys/src/cmd/creepy/net.h --- a/sys/src/cmd/creepy/net.h Tue Mar 20 20:00:07 2012 +0100 +++ b/sys/src/cmd/creepy/net.h Tue Mar 20 20:14:04 2012 +0100 @@ -30,10 +30,15 @@ int archived; int cflags; /* OCERR|OCEND */ int consopen; /* for flush. has /cons open? */ - char *uid; + int uid; uvlong loff; /* last offset, for dir reads */ int lidx; /* next dir entry index to read */ + char* buf; /* for statsread() */ + + int afd; /* for afids */ + int authok; /* for afids */ + AuthRpc *rpc; /* for afids */ }; struct Rpc @@ -86,6 +91,7 @@ int fd; int cfd; char *addr; + int uid; ulong msize; QLock wlk; /* lock for writing replies to the client */ @@ -105,3 +111,4 @@ extern ulong ncalls[]; extern char *callname[]; extern Alloc fidalloc, rpcalloc, clialloc; +extern int noauth;