# HG changeset patch # User Francisco J Ballesteros # Date 1330293212 -3600 # Node ID 877e1ea171e24e11ea29811acb1b143295bff4d4 # Parent 9d88846ae23b2463252b1b8aef48f968edb7e34d Cfs: is gone, it's now creepy I thought I already submit this. Trying again... R=nixiedev CC=nix-dev http://codereview.appspot.com/5695069 diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/attr.c --- a/sys/src/cmd/Cfs/attr.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "fns.h" - -/* - * Attribute handling - */ - -typedef struct Adef Adef; - -struct Adef -{ - char* name; - long (*wattr)(Memblk*, void*, long); - long (*rattr)(Memblk*, void*, long); -}; - -static long wname(Memblk*, void*, long); -static long rname(Memblk*, void*, long); - -static Adef adef[] = -{ - {"name", wname, rname}, -}; - -ulong -embedattrsz(Memblk *f) -{ - ulong sz; - - sz = f->d.asize; - if(sz < Dminattrsz) - sz = Dminattrsz; - if(sz > Embedsz || Embedsz - sz < sizeof(Dentry)) - sz = Embedsz; - return sz; -} - -void -gmeta(Fmeta *meta, void *buf, ulong nbuf) -{ - Dmeta *d; - char *p, *x; - int i; - - if(nbuf < sizeof *d) - error("metadata buffer too small"); - d = buf; - meta->id = d->id; - meta->mode = d->mode; - meta->mtime = d->mtime; - meta->length = d->length; - - if(d->ssz[FMuid] + sizeof *d > nbuf || - d->ssz[FMgid] + sizeof *d > nbuf || - d->ssz[FMmuid] + sizeof *d > nbuf || - d->ssz[FMname] + sizeof *d > nbuf) - error("corrupt meta: wrong string size"); - - p = (char*)(&d[1]); - x = p; - for(i = 0; i < nelem(d->ssz); i++){ - if(x[d->ssz[i]-1] != 0) - error("corrupt meta: unterminated string"); - x += d->ssz[i]; - } - - meta->uid = p; - p += d->ssz[FMuid]; - meta->gid = p; - p += d->ssz[FMgid]; - meta->muid = p; - p += d->ssz[FMmuid]; - meta->name = p; -} - -static ulong -metasize(Fmeta *meta) -{ - ulong n; - - n = sizeof(Dmeta); - n += strlen(meta->uid) + 1; - n += strlen(meta->gid) + 1; - n += strlen(meta->muid) + 1; - n += strlen(meta->name) + 1; - /* - * BUG: meta->attr - */ - return n; -} - -/* - * Pack the metadata into buf. - * pointers in meta are changed to refer to the packed data. - * Return pointer past the packed metadata. - * The caller is responsible for ensuring that metadata fits in buf. - */ -ulong -pmeta(void *buf, ulong nbuf, Fmeta *meta) -{ - Dmeta *d; - char *p, *bufp; - ulong sz; - - sz = metasize(meta); - if(sz > nbuf){ - sysfatal("bug: allocate and use ablk"); - error("attributes are too long"); - } - d = buf; - bufp = buf; - d->id = meta->id; - d->mode = meta->mode; - d->mtime = meta->mtime; - d->length = meta->length; - - p = (char*)(&d[1]); - d->ssz[FMuid] = strlen(meta->uid) + 1; - strcpy(p, meta->uid); - meta->uid = p; - p += d->ssz[FMuid]; - - d->ssz[FMgid] = strlen(meta->gid) + 1; - strcpy(p, meta->gid); - meta->gid = p; - p += d->ssz[FMgid]; - - d->ssz[FMmuid] = strlen(meta->muid) + 1; - strcpy(p, meta->muid); - meta->muid = p; - p += d->ssz[FMmuid]; - - d->ssz[FMname] = strlen(meta->name) + 1; - strcpy(p, meta->name); - meta->name = p; - p += d->ssz[FMname]; - - assert(p - bufp <= sz); /* can be <, to leave room for growing */ - return sz; -} - -static long -wname(Memblk *f, void *buf, long len) -{ - char *p, *old; - ulong maxsz; - - p = buf; - if(len < 1 || p[len-1] != 0) - error("name must end in \\0"); - old = f->mf->name; - f->mf->name = p; - maxsz = embedattrsz(f); - if(metasize(f->mf) > maxsz){ - f->mf->name = old; - fprint(2, "%s: bug: no attribute block implemented\n", argv0); - error("no room to grow metadata"); - } - /* name goes last, we can pack in place */ - f->d.asize = pmeta(f->d.embed, maxsz, f->mf); - changed(f); - return len; -} - -static long -rname(Memblk *f, void *buf, long len) -{ - long l; - - l = strlen(f->mf->name) + 1; - if(l > len) - error("buffer too short"); - strcpy(buf, f->mf->name); - return l; -} - -long -dfwattr(Memblk *f, char *name, void *val, long nval) -{ - int i; - - isfile(f); - iswlocked(f); - for(i = 0; i < nelem(adef); i++) - if(strcmp(adef[i].name, name) == 0) - return adef[i].wattr(f, val, nval); - error("user defined attributes not yet implemented"); - return -1; -} - -long -dfrattr(Memblk *f, char *name, void *val, long count) -{ - int i; - - isfile(f); - isrlocked(f); - for(i = 0; i < nelem(adef); i++) - if(strcmp(adef[i].name, name) == 0) - return adef[i].rattr(f, val, count); - error("user defined attributes not yet implemented"); - return -1; -} - diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/conf.h --- a/sys/src/cmd/Cfs/conf.h Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ - - -#define TESTING - -enum -{ - KiB = 1024UL, - MiB = KiB * 1024UL, - GiB = MiB * 1024UL, - -#ifdef TESTING - Incr = 2, - Fmemsz = 1*MiB, /* max size of in-memory file data */ - Fsysmem = 1*MiB, /* size of fsys data in memory */ - Dminfree = 100000, /* min nb. of free blocks in disk */ - - /* disk parameters; don't change */ - Dblksz = 512UL, /* disk block size */ - Dblkhdrsz = 2*BIT64SZ, - Ndptr = 2, /* # of direct data pointers */ - Niptr = 2, /* # of indirect data pointers */ -#else - Incr = 16, - Fmemsz = 64 * MiB, /* max size of in-memory file data */ - Fsysmem = 2*GiB, /* size of fsys data in memory */ - Dminfree = 1000, /* min nb. of free blocks in disk */ - - /* disk parameters; don't change */ - Dblksz = 16*KiB, /* disk block size */ - Dblkhdrsz = 2*BIT64SZ, - Ndptr = 8, /* # of direct data pointers */ - Niptr = 4, /* # of indirect data pointers */ -#endif - - Dminattrsz = Dblksz/2, /* min size for attributes */ - - /* - * The format of the disk is: - * blk 0: unused - * blk 1: super - * Nblkgrpsz blocks (1st is ref, Nblkgrpsz-1 are data) - * ... - * Nblkgrpsz blocks (1st is ref, Nblkgrpsz-1 are data) - * - */ - Nblkgrpsz = (Dblksz - Dblkhdrsz) / BIT64SZ, - Dblk0addr = 2*Dblksz, - - /* - * 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 */ - Fhashsz = 7919, /* size of file hash (plan9 has 35454 files). */ - -}; - diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/dbg.c --- a/sys/src/cmd/Cfs/dbg.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ - -char dbg[256]; - diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/dbg.h --- a/sys/src/cmd/Cfs/dbg.h Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -/* - * 'd': general debug - * 'D': disk - */ -#define dDprint if(!dbg['D']){}else print -extern char dbg[]; diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/dblk.c --- a/sys/src/cmd/Cfs/dblk.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,482 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "fns.h" - -/* - * disk blocks. - * see dk.h - */ - -void -dbclear(u64int addr, int type) -{ - static Diskblk d; - static QLock lk; - - dDprint("dbclear d%#ullx type DB%s\n", addr, tname[type]); - qlock(&lk); - d.tag = TAG(addr, type); - d.epoch = now(); - if(pwrite(fs->fd, &d, sizeof d, addr) != Dblksz){ - qlock(&lk); - error("dbclear: %r"); - } - qunlock(&lk); -} - -void -meltedref(Memblk *rb) -{ - if(rb->frozen && rb->dirty){ - if(catcherror()) - sysfatal("writing ref: %r"); - dbwrite(rb); - noerror(); - } - rb->frozen = rb->dirty = 0; -} - -/* - * BUG: the free list of blocks using entries in the ref blocks - * shouldn't span all those blocks as it does now. To prevent - * massive loses of free blocks each DBref block must keep its own - * little free list, and all blocks with free entries must be linked - * in the global list. - * This keeps locality and makes it less likely that a failure in the - * middle of the sync for the free list destroyes the entire list. - */ - -u64int -newblkaddr(void) -{ - u64int addr, naddr; - - qlock(fs); - - /* - * Caution: can't acquire new locks while holding blklk - * only dbgetref may raise an error, but we don't hold the - * lock while calling it. - */ -Again: - if(fs->super == nil) - addr = Dblksz; - else if(fs->super->d.eaddr < fs->limit){ - addr = fs->super->d.eaddr; - fs->super->d.eaddr += Dblksz; - changed(fs->super); - /* - * ref blocks are allocated and initialized on demand, - * and they must be zeroed before used. - * do this holding the lock so others find everything - * initialized. - */ - if(((addr-Dblk0addr)/Dblksz)%Nblkgrpsz == 0){ - dDprint("new ref blk addr = d%#ullx\n", addr); - if(catcherror()){ - qunlock(fs); - error(nil); - } - dbclear(addr, DBref); /* fs initialization */ - noerror(); - addr += Dblksz; - fs->super->d.eaddr += Dblksz; - } - }else if(fs->super->d.free != 0){ - addr = fs->super->d.free; - - qunlock(fs); - naddr = dbgetref(addr); /* acquires locks */ - qlock(fs); - if(addr != fs->super->d.free){ - /* had a race */ - goto Again; - } - fs->super->d.free = naddr; - fs->super->d.nfree -= 1; - changed(fs->super); - }else{ - /* backward compatible with fossil */ - error("disk is full"); - } - qunlock(fs); - okaddr(addr); - - dDprint("newblkaddr = d%#ullx\n", addr); - return addr; -} - -u64int -addrofref(u64int refaddr, int idx) -{ - u64int bno; - - bno = (refaddr - Dblk0addr)/Dblksz; - bno *= Nblkgrpsz; - bno += idx; - - return Dblk0addr + bno*Dblksz; -} - -u64int -refaddr(u64int addr, int *idx) -{ - u64int bno, refaddr; - - addr -= Dblk0addr; - bno = addr/Dblksz; - *idx = bno%Nblkgrpsz; - refaddr = Dblk0addr + bno/Nblkgrpsz * Nblkgrpsz * Dblksz; - dDprint("refaddr d%#ullx = d%#ullx[%d]\n", - Dblk0addr + addr, refaddr, *idx); - return refaddr; -} - -/* - * db*ref() functions update the on-disk reference counters. - * memory blocks use Memblk.Ref instead. - */ - -u64int -dbgetref(u64int addr) -{ - Memblk *rb; - u64int raddr, ref; - int i; - - if(addr == 0) - return 0; - - if(addr == Noaddr ) /* root; 1 ref by the face */ - return 1; - - raddr = refaddr(addr, &i); - rb = dbget(DBref, raddr); - qlock(fs); - meltedref(rb); - ref = rb->d.ref[i]; - qunlock(fs); - mbput(rb); - return ref; -} - -void -dbsetref(u64int addr, u64int ref) -{ - Memblk *rb; - u64int raddr; - int i; - - dDprint("dbsetref %#ullx = %ulld\n", addr, ref); - if(addr < Dblk0addr) - sysfatal("dbsetref"); - raddr = refaddr(addr, &i); - rb = dbget(DBref, raddr); - qlock(fs); - meltedref(rb); - rb->d.ref[i] = ref; - changed(rb); - qunlock(fs); - mbput(rb); -} - -void -dbincref(u64int addr) -{ - Memblk *rb; - u64int raddr; - int i; - - dDprint("dbincref %#ullx\n", addr); - raddr = refaddr(addr, &i); - rb = dbget(DBref, raddr); - qlock(fs); - meltedref(rb); - rb->d.ref[i]++; - changed(rb); - qunlock(fs); - mbput(rb); -} - -u64int -dbdecref(u64int addr) -{ - Memblk *rb; - u64int raddr, ref; - int i; - - if(addr < Dblk0addr) - sysfatal("dbdecref"); - dDprint("dbdecref %#ullx\n", addr); - raddr = refaddr(addr, &i); - rb = dbget(DBref, raddr); - meltedref(rb); - qlock(fs); - rb->d.ref[i]--; - ref = rb->d.ref[i]; - changed(rb); - if(ref == 0){ - rb->d.ref[i] = fs->super->d.free; - fs->super->d.free = addr; - fs->super->d.nfree += 1; - changed(fs->super); - changed(rb); - } - qunlock(fs); - mbput(rb); - return ref; -} - -static Mfile* -mfalloc(void) -{ - Mfile *mf; - - qlock(fs); - mf = fs->mfree; - if(mf != nil){ - fs->mfree = mf->next; - mf->next = nil; - } - qunlock(fs); - if(mf == nil) - mf = mallocz(sizeof *mf, 1); - return mf; -} - -Memblk* -dballoc(uint type) -{ - Memblk *b; - u64int addr; - int root; - - root = (type == Noaddr); - addr = Noaddr; - if(root) - type = DBfile; - else - addr = newblkaddr(); - dDprint("dballoc DB%s\n", tname[type]); - b = mballoc(addr); - b->d.tag = TAG(b->addr,type); - changed(b); - if(catcherror()){ - mbput(b); - error(nil); - } - if(addr != Noaddr && addr >= Dblk0addr) - dbsetref(addr, 1); - if(type == DBfile) - b->mf = mfalloc(); - mbhash(b); - dDprint("dballoc DB%s -> %H\n", tname[type], b); - noerror(); - return b; -} - -/* - * BUG: these should ensure that all integers are converted between - * little endian (disk format) and the machine endianness. - * We know the format of all blocks and the type of all file - * attributes. Those are the integers to convert to fix the bug. - */ -Memblk* -hosttodisk(Memblk *b) -{ - incref(b); - if(!TAGADDROK(b->d.tag, b->addr)) - sysfatal("hosttodisk: bad tag"); - return b; -} -void -disktohost(Memblk *b) -{ - static union - { - u64int i; - uchar m[BIT64SZ]; - } u; - - u.i = 0x1122334455667788ULL; - if(u.m[0] != 0x88) - sysfatal("fix hosttodisk/disktohost for big endian"); - - if(!TAGADDROK(b->d.tag, b->addr)){ -print("disktohost: %H", b); - error("disktohost: bad tag"); -} -} - -long -dbwrite(Memblk *b) -{ - Memblk *nb; - - dDprint("dbwrite %H",b); - - nb = hosttodisk(b); - nb->d.epoch = now(); - if(pwrite(fs->fd, &nb->d, sizeof nb->d, nb->addr) != Dblksz){ - mbput(nb); - error("dbwrite: %r"); - } - mbput(nb); - return Dblksz; -} - -long -dbread(Memblk *b) -{ - long tot, nr; - uchar *p; - - dDprint("dbread m%#p d%#ullx\n", b, b->addr); - - p = b->d.ddata; - for(tot = 0; tot < Dblksz; tot += nr){ - nr = pread(fs->fd, p+tot, Dblksz-tot, b->addr + tot); - if(nr == 0) - error("eof on disk"); - if(nr <= 0){ - error("dbread: %r"); - return -1; - } - } - assert(tot == sizeof b->d); - - disktohost(b); - if(TAGTYPE(b->d.tag) != DBref) - b->frozen = 1; - if(0)dDprint("dbread %H", b); - - return tot; -} - -/* - * Directories are fully loaded by dbget. - * Their data is never removed from memory unless the - * entire directory is removed from memory. - */ -Memblk* -dbget(uint type, u64int addr) -{ - Memblk *b; - u64int tag; - - dDprint("dbget DB%s d%#ullx\n", tname[type], addr); - okaddr(addr); - tag = TAG(addr,type); - b = mbget(addr); - if(b != nil){ - if(b->d.tag != tag) - sysfatal("dbget: got bad tag"); - return b; - } - - /* - * others might request the same block while we read it. - * the first one hashing it wins; no locks. - */ - b = mballoc(addr); - if(catcherror()){ - mbput(b); - error(nil); - } - dbread(b); - if(b->d.tag != tag){ - dDprint("dbget: wanted DB%s; got DB%s\n", - tname[type], tname[TAGTYPE(b->d.tag)]); -abort(); - sysfatal("dbget: read bad tag %#ullx %#ullx", b->d.tag, tag); - } - if(type == DBfile){ - assert(b->mf == nil); - b->mf = mfalloc(); - gmeta(b->mf, b->d.embed, Embedsz); - b->written = 1; - } - - noerror(); - b = mbhash(b); - return b; -} - -/* - * caller responsible for locking. - */ -Memblk* -dbdup(Memblk *b) -{ - Memblk *nb; - uint type; - int i; - Mfile *nm, *m; - - type = TAGTYPE(b->d.tag); - nb = dballoc(type); - switch(type){ - case DBfree: - case DBref: - case DBsuper: - case DBattr: - sysfatal("dbdup: DB%s", tname[type]); - case DBdata: - memmove(nb->d.data, b->d.data, Dblkdatasz); - break; - case DBfile: - isrlocked(b); - isloaded(b); - nb->d.asize = b->d.asize; - nb->d.aptr = b->d.aptr; - if(nb->d.aptr != 0) - dbincref(b->d.aptr); - for(i = 0; i < nelem(b->d.dptr); i++){ - nb->d.dptr[i] = b->d.dptr[i]; - if(nb->d.dptr[i] != 0) - dbincref(b->d.dptr[i]); - } - for(i = 0; i < nelem(b->d.iptr); i++){ - nb->d.iptr[i] = b->d.iptr[i]; - if(nb->d.iptr[i] != 0) - dbincref(b->d.iptr[i]); - } - memmove(nb->d.embed, b->d.embed, Embedsz); - nm = nb->mf; - m = b->mf; - gmeta(nm, nb->d.embed, Embedsz); - if(m->nchild > 0){ - if(nm->nachild < m->nchild){ - nm->child = realloc(nm->child, m->nchild*sizeof(Child)); - nm->nachild = m->nchild; - nm->nchild = m->nchild; - } - for(i = 0; i < nm->nchild; i++){ - nm->child[i] = m->child[i]; - nm->child[i].f->mf->parent = nb; - incref(nm->child[i].f); - incref(nm->child[i].b); - } - } - break; - default: - if(type < DBptr0 || type >= DBptr0 + Niptr) - sysfatal("dbdup: type %d", type); - for(i = 0; i < Dptrperblk; i++){ - nb->d.ptr[i] = b->d.ptr[i]; - if(nb->d.ptr[i] != 0) - dbincref(b->d.ptr[i]); - } - } - changed(nb); - return nb; -} - diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/disk Binary file sys/src/cmd/Cfs/disk has changed diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/dk.h --- a/sys/src/cmd/Cfs/dk.h Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,360 +0,0 @@ -typedef struct Fmeta Fmeta; -typedef struct Child Child; -typedef struct Ddatablk Ddatablk; -typedef struct Dptrblk Dptrblk; -typedef struct Drefblk Drefblk; -typedef struct Dattrblk Dattrblk; -typedef struct Dfileblk Dfileblk; -typedef struct Dsuperblk Dsuperblk; -typedef union Diskblk Diskblk; -typedef struct Diskblkhdr Diskblkhdr; -typedef struct Memblk Memblk; -typedef struct Fsys Fsys; -typedef struct Dentry Dentry; -typedef struct Dmeta Dmeta; -typedef struct Blksl Blksl; -typedef struct Mfile Mfile; - -/* - * Conventions on the data structures: - * - * References: - * - Mem refs include the reference from the hash (to keep the block) - * plus from external structures/users. Thus: - * - those with ref=1 are just kept cached in the hash - * - those with ref=2 are referenced also by the tree - * (or the superblock; does not apply to DBref blocks) - * - those with ref >2 are in use - * - Disk refs count only references within the tree on disk. - * (perhaps loaded in memory waiting for a further sync) - * - Children do not imply new refs to the parents. - * - * Locking & Assumptions: - * - /active is *never* found on disk, it's memory-only. - * - b->addr is worm. - * - b->next is locked by the hash bucked lock - * - blocks are added to the end of the hash chain. - * - blocks are locked by the file responsible for them, when not frozen. - * - super, disk refs, block allocation, free list, ... protected by fs lock - * - We try not to hold more than one lock, using the - * reference counters when we need to be sure that - * an unlocked resource does not vanish. - * - parents of blocks in memory are in memory - * - reference blocks are never removed from memory. - * - disk refs frozen while waiting to be to disk during a fs freeze. - * in which case db*ref functions write the block in place and melt it. - * - the block epoch number for a on-disk block is the time when it - * was written (thus it's archived "/" has a newer epoch). - * - * Lock order: - * - fs & super: while locked can't acquire fs or blocks. - * - parent block -> child - * (but a DBfile protects all ptr and data blocks under it). - * - block -> ref block - */ - -enum -{ - /* block types */ - DBfree = 0, - DBref, - DBattr, - DBfile, - DBsuper, - DBdata, /* direct block */ - DBptr0 = DBdata+1, /* simple-indirect block */ - /* double */ - /* triple */ - /*...*/ -}; - -/* - * ##### On disk structures. ##### - * - * All on-disk integer values are little endian. - * - * blk 0: unused - * blk 1: super - * ref blk + Nblkgrpsz-1 blocks - * ... - * ref blk + Nblkgrpsz-1 blocks - * - * The code assumes these structures are packed. - * Be careful if they are changed to make things easy for the - * compiler and keep them naturally aligned. - */ - -struct Ddatablk -{ - uchar data[1]; /* raw memory */ -}; - -struct Dptrblk -{ - u64int ptr[1]; /* array of block addresses */ -}; - -struct Drefblk -{ - u64int ref[1]; /* disk RC or next block in free list */ -}; - -struct Dattrblk -{ - u64int next; /* next block used for attribute data */ - uchar attr[1]; /* raw attribute data */ -}; - -/* - * directory entry. contents of data blocks in directories. - * Each block stores only an integral number of Dentries, for simplicity. - */ -struct Dentry -{ - u64int file; /* file address or 0 when unused */ -}; - -/* - * The trailing part of the file block is used to store attributes - * and initial file data. - * At least Dminattrsz is reserved for attributes, at most - * all the remaining embedded space. - * Past the attributes, starts the file data. - * If more attribute space is needed, an attribute block is allocated. - * For huge attributes, it is suggested that a file is allocated and - * the attribute value refers to that file. - * The pointer in iptr[n] is an n-indirect data pointer. - * - * Directories are also files, but their data is simply an array of - * Dentries. - */ -struct Dfileblk -{ - u64int asize; /* attribute size */ - u64int aptr; /* attribute block pointer */ - u64int dptr[Ndptr]; /* direct data pointers */ - u64int iptr[Niptr]; /* indirect data pointers */ - uchar embed[1]; /* embedded attrs and data */ -}; - -enum -{ - FMuid = 0, /* strings in mandatory attributes */ - FMgid, - FMmuid, - FMname, - FMnstr, -}; - -struct Dmeta /* mandatory metadata */ -{ - u64int id; /* ctime, actually */ - u64int mode; - u64int mtime; - u64int length; - u16int ssz[FMnstr]; - /* uid\0gid\0muid\0name\0 */ -}; - -/* - * Superblock. - * The stored tree is: - * archive/ root of the archived tree - * - * ... - * (/ and /active are only memory and never on disk, parts - * under /active that are on disk are shared with entries in /archive) - */ -struct Dsuperblk -{ - u64int free; /* first free block on list */ - u64int eaddr; /* end of the assigned disk portion */ - u64int root[16]; /* address of /archive in disk */ - u64int nfree; /* # of blocks in free list */ - u64int dblksz; /* only for checking */ - u64int nblkgrpsz; /* only for checking */ - u64int dminattrsz; /* only for checking */ - uchar vac0[24]; /* score for last venti archive + 4pad */ - uchar vac1[24]; /* score for previous venti archive + 4pad */ -}; - -enum -{ - Noaddr = ~0UL /* null address, for / */ -}; - -#define TAG(addr,type) ((addr)<<8|((type)&0x7F)) -#define TAGTYPE(t) ((t)&0x7F) -#define TAGADDROK(t,addr) (((t)&~0xFF) == ((addr)<<8)) - -/* - * disk blocks - */ - -/* - * header for all disk blocks. - * Those using on-disk references keep them at a DBref block - */ -struct Diskblkhdr -{ - u64int tag; /* block tag */ - u64int epoch; /* block epoch */ -}; - -union Diskblk -{ - struct{ - Diskblkhdr; - union{ - Ddatablk; /* data block */ - Dptrblk; /* pointer block */ - Drefblk; /* reference counters block */ - Dattrblk; /* attribute block */ - Dfileblk; /* file block */ - Dsuperblk; - }; - }; - uchar ddata[Dblksz]; -}; - -/* - * These are derived. - * Artificially lowered for testing to exercise indirect blocks and lists. - */ -enum -{ - Dblkdatasz = sizeof(Diskblk) - sizeof(Diskblkhdr), - Embedsz = Dblkdatasz - sizeof(Dfileblk), - -#ifdef TESTING - Dentryperblk = 4, - Dptrperblk = 4, - Drefperblk = 4, -#else - Dentryperblk = Dblkdatasz / sizeof(Dentry), - Dptrperblk = Dblkdatasz / sizeof(u64int), - Drefperblk = Dblkdatasz / sizeof(u64int), -#endif -}; - - -/* - * File attributes are name/value pairs. - * By now, only mandatory attributes are implemented, and - * have names implied by their position in the Dmeta structure. - */ - -/* - * ##### On memory structures. ##### - */ - -/* - * The first time a directory data is used, it is fully loaded and - * a Child list refers to the data blocks, to simplify navigation. - */ -struct Child -{ - Memblk *f; /* actual child */ - Memblk *b; /* data block containing it's dentry */ - Dentry *d; /* loaded dentry */ -}; - -/* - * File metadata - */ -struct Fmeta -{ - Dmeta; - char *uid; - char *gid; - char *muid; - char *name; -}; - -/* - * On memory file information. - */ -struct Mfile -{ - RWLock; - Fmeta; - union{ - Memblk *parent; /* most recent parent */ - Mfile *next; /* in free Mfile list */ - }; - - Memblk* lastb; /* memo: last returned data block */ - ulong lastbno; /* for the last asked block # */ - - Child *child; /* direct references to loaded children */ - int nchild; /* number of used children in child */ - int nachild; /* number of allocated chilren in child */ -}; - -/* - * memory block - */ -struct Memblk -{ - Ref; - u64int addr; /* block address */ - Memblk *next; /* in hash or free list */ - - union{ - Memblk *rnext; /* in list of DBref blocks */ - Mfile *mf; /* DBfile on memory info. */ - }; - - int dirty; /* must be written */ - int frozen; /* is frozen */ - int written; /* no need to scan this for dirties */ - - Diskblk d; -}; - -/* - * Slice into a block, used to read/write file blocks. - */ -struct Blksl -{ - Memblk *b; - void *data; - long len; -}; - -struct Fsys -{ - QLock; - struct{ - RWLock; - Memblk *b; - } fhash[Fhashsz]; /* hash of blocks by address */ - - Memblk *blk; /* static global array of memory blocks */ - usize nblk; /* # of entries used */ - usize nablk; /* # of entries allocated */ - usize nused; /* blocks in use */ - usize nfree; /* free blocks */ - - Memblk *free; /* free list of unused blocks in blk */ - Mfile *mfree; /* unused list */ - - Memblk *refs; /* list of DBref blocks (also hashed) */ - - Memblk *super; /* locked by blklk */ - Memblk *root; /* only in memory */ - Memblk *active; /* /active */ - Memblk *archive; /* /archive */ - - Memblk *fzsuper; /* frozen super */ - - char *dev; /* name for disk */ - int fd; /* of disk */ - usize limit; /* address for end of disk */ -}; - -#pragma varargck type "H" Memblk* - - -extern char*tname[]; -extern Fsys*fs; diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/fblk.c --- a/sys/src/cmd/Cfs/fblk.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,628 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "fns.h" - -/* - * File block tools. - * Should be used mostly by file.c, where the interface is kept. - * see dk.h - */ - -void -isfile(Memblk *d) -{ - if(TAGTYPE(d->d.tag) != DBfile || d->mf == nil) - sysfatal("%Hnot a DBfile at %#p", d, getcallerpc(&d)); -} - -void -isdir(Memblk *d) -{ - if(TAGTYPE(d->d.tag) != DBfile || d->mf == nil) - sysfatal("%Hnot a DBfile at %#p", d, getcallerpc(&d)); - if((d->mf->mode&DMDIR) == 0) - sysfatal("%Hnot a directory at %#p", d, getcallerpc(&d)); -} - -void -isnotdir(Memblk *d) -{ - if(TAGTYPE(d->d.tag) != DBfile || d->mf == nil) - sysfatal("%Hnot a DBfile at %#p", d, getcallerpc(&d)); - if((d->mf->mode&DMDIR) != 0) - sysfatal("%His a directory at %#p", d, getcallerpc(&d)); -} - -void -isloaded(Memblk *d) -{ - if(TAGTYPE(d->d.tag) != DBfile || d->mf == nil) - sysfatal("%Hnot a DBfile at %#p", d, getcallerpc(&d)); - if((d->mf->mode&DMDIR) != 0) - if(d->mf->length > 0 && d->mf->child == nil){ - abort(); - sysfatal("%Hnot loaded at %#p", d, getcallerpc(&d)); - } -} - -void -iswlocked(Memblk *b) -{ - if(TAGTYPE(b->d.tag) != DBfile || b->mf == nil) - sysfatal("%Hnot a DBfile at %#p", b, getcallerpc(&b)); - if(canrlock(b->mf)) - sysfatal("iswlocked at %#p", getcallerpc(&b)); -} - -void -isrlocked(Memblk *b) -{ - if(TAGTYPE(b->d.tag) != DBfile || b->mf == nil) - sysfatal("%Hnot a DBfile at %#p", b, getcallerpc(&b)); - if(canwlock(b->mf)) - sysfatal("isrlocked at %#p", getcallerpc(&b)); -} - - -static Memblk* -getmelted(uint type, u64int *addrp) -{ - Memblk *b, *nb; - - if(*addrp == 0){ - b = dballoc(type); - *addrp = b->addr; - incref(b); - return b; - } - - b = dbget(type, *addrp); - if(b->frozen == 0) - return b; - - nb = dbdup(b); - dbdecref(b->addr); - mbput(b); - *addrp = nb->addr; - incref(nb); - return nb; -} - -/* - * Get a file data block, perhaps allocating it on demand - * if mkit. The file must be r/wlocked and melted if mkit. - */ -static Memblk* -dfblk(Memblk *f, ulong bno, int mkit) -{ - ulong prev, nblks; - int i, idx, nindir, type; - Memblk *b, *pb; - u64int *addrp; - Mfile *m; - - if(0)dDprint("DF0 %H", f); - m = f->mf; - if(mkit){ - iswlocked(f); - ismelted(f); - }else - isrlocked(f); - - if(bno != 0 && m->lastb != nil){ - if(bno == m->lastbno){ - if(!mkit || !m->lastb->frozen){ - incref(m->lastb); - return m->lastb; - } - }else if(bno == m->lastbno + 1 && !mkit){ - /* BUG: read ahead */ - } - if(m->lastb != nil) - mbput(m->lastb); - m->lastb = nil; - } - m->lastbno = bno; - - /* - * bno: block # relative to the the block we are looking at. - * prev: # of blocks before the current one. - */ - prev = 0; - - /* - * Direct block? - */ - if(bno < nelem(f->d.dptr)){ - if(mkit) - b = getmelted(DBdata, &f->d.dptr[bno]); - else - b = dbget(DBdata, f->d.dptr[bno]); - goto Found; - } - - bno -= nelem(f->d.dptr); - prev += nelem(f->d.dptr); - - /* - * Indirect block - * nblks: # of data blocks addressed by the block we look at. - */ - nblks = Dptrperblk; - for(i = 0; i < nelem(f->d.iptr); i++){ - if(bno < nblks) - break; - bno -= nblks; - prev += nblks; - nblks *= Dptrperblk; - } - if(i == nelem(f->d.iptr)) - sysfatal("fblkaddr"); - - type = DBptr0+i; - dDprint("dfblk indirect DB%s nblks %uld (ppb %ud) bno %uld\n", - tname[type], nblks, Dptrperblk, bno); - pb = f; - incref(pb); - addrp = &f->d.iptr[i]; - if(mkit) - b = getmelted(type, addrp); - else - b = dbget(type, *addrp); - - /* invariant at the loop header: - * b: DBptr block we are looking at. - * nblks: # of data blocks addressed by b - * pb: parent of b - * addrp: ptr to b within fb. - */ - if(catcherror()){ - mbput(pb); - mbput(b); - error(nil); - } - for(nindir = i+1; nindir >= 0; nindir--){ - dDprint("indir DB%s d%#ullx nblks %uld ptrperblk %d bno %uld\n", - tname[DBdata+nindir], *addrp, nblks, Dptrperblk, bno); - dDprint(" in %H", b); - idx = 0; - if(nindir > 0){ - nblks /= Dptrperblk; - idx = bno/nblks; - } - if(*addrp == 0 && !mkit){ - /* hole */ - b = nil; - }else{ - assert(type >= DBdata); - if(mkit) - b = getmelted(type, addrp); - else - b = dbget(type, *addrp); - addrp = &b->d.ptr[idx]; - mbput(pb); - pb = b; - } - USED(&b); /* force to memory in case of error */ - USED(&pb); /* force to memory in case of error */ - bno -= idx * nblks; - prev += idx * nblks; - type--; - } - noerror(); - -Found: - if(0){ - if(b != nil) - incref(b); - m->lastb = b; /* memo the last search */ - }else - m->lastb = nil; - - if(0)dDprint("DF1 %H%H", f,b); - return b; -} - -static void -fresize(Memblk *f, uvlong nsize) -{ - Dmeta *d; - - f->mf->length = nsize; - d = (Dmeta*)f->d.embed; - d->length = nsize; -} - -/* - * Return a block slice for data in f. - * - * Only a single block is returned, the caller may call dfslice - * as many times as needed. - * (If there's a hole in the file, Blksl.data == nil && Blksl.len > 0) - * - * If mkit, the data block (and middle pointer blocks) - * are allocated/melted if needed, in such case, the length of the file - * is updated to the given offset. Otherwise, the file length is a limit. - * - * The file must be r/wlocked by the caller, and melted if mkit. - * The block is returned unlocked, but still protected by the file lock. - */ -Blksl -dfslice(Memblk *f, ulong len, uvlong off, int iswr) -{ - Blksl sl; - ulong boff, doff, dlen, bno; - - dDprint("slice off %#ullx len %#ulx wr=%d at m%#p\n%H", off, len, iswr, f,f); - memset(&sl, 0, sizeof sl); - - if(iswr){ - iswlocked(f); - ismelted(f); - }else{ - isrlocked(f); - if(off >= f->mf->length) - goto Done; - } - doff = embedattrsz(f); - dlen = Embedsz - doff; - if(off < dlen){ - sl.b = f; - incref(f); - sl.data = f->d.embed + doff + off; - sl.len = dlen - off; - }else{ - bno = (off-dlen) / Dblkdatasz; - boff = (off-dlen) % Dblkdatasz; - - sl.b = dfblk(f, bno, iswr); - if(iswr) - ismelted(sl.b); - if(sl.b != nil) - sl.data = sl.b->d.data + boff; - sl.len = Dblkdatasz - boff; - } - - if(sl.len > len) - sl.len = len; - if(off + sl.len > f->mf->length) - if(iswr) - fresize(f, off + sl.len); - else - sl.len = f->mf->length - off; -Done: - if(sl.b == nil){ - dDprint("slice-> null with len %#ulx\n", sl.len); - return sl; - } - assert(sl.b->ref > 1); - if(TAGTYPE(sl.b->d.tag) == DBfile) - dDprint("slice -> off %#ulx len %#ulx at m%#p fsz %#ullx\n", - (uchar*)sl.data - sl.b->d.embed, sl.len, sl.b, f->mf->length); - else - dDprint("slice-> off %#ulx len %#ulx at m%#p fsz %#ullx\n", - (uchar*)sl.data - sl.b->d.data, sl.len, sl.b, f->mf->length); - return sl; -} - -/* - * These two ones un/link f to the child list of d, - * but the children do not imply further references to the parent. - */ - -static Child* -addchild(Memblk *d, Memblk *f) -{ - Mfile *m; - Child *c; - - isdir(d); - isfile(f); - m = d->mf; - if(m->nchild == m->nachild){ - m->nachild += Incr; - m->child = realloc(m->child, m->nachild*sizeof(Child)); - } - c = &m->child[m->nchild++]; - memset(c, 0, sizeof *c); - c->f = f; - f->mf->parent = d; - return c; -} - -void -delchild(Memblk *d, Child *c) -{ - Mfile *m; - int i; - - isdir(d); - isloaded(d); - m = d->mf; - i = c - m->child; - if(i < m->nchild-1) - m->child[i] = m->child[m->nchild-1]; - m->nchild--; - c->f->mf->parent = nil; -} - -static Child* -getchild(Memblk *d, Memblk *f) -{ - Mfile *m; - int i; - - isdir(d); - isfile(f); - isloaded(d); - m = d->mf; - for(i = 0; i < m->nchild; i++) - if(m->child[i].f == f) - break; - if(i == m->nchild) - sysfatal("findchild: not found"); - return &m->child[i]; -} - -/* - * does not dbincref(f) - * caller locks both d and f - * No reference to the parent is added because of the new - * e.g. block referenced by f->child[n].b must be loaded as long - * as its child entry is alive. - */ -void -dflink(Memblk *d, Memblk *f) -{ - Blksl sl; - Dentry *de; - uvlong off; - Child *c; - - dDprint("dflink\n %H %H", d, f); - iswlocked(d); - ismelted(d); - isdir(d); - if(d->mf->length > 0 && d->mf->child == nil) - dfloaddir(d, 1); - - c = addchild(d, f); - if(catcherror()){ - delchild(d, c); - error(nil); - } - off = 0; - for(;;){ - sl = dfslice(d, sizeof(Dentry), off, 1); - if(sl.len == 0) - break; - ismelted(sl.b); - off += sl.len; - if(sl.len < sizeof(Dentry)){ /* trailing part in block */ - mbput(sl.b); - continue; - } - de = sl.data; - if(de->file == 0){ - c->d = de; - c->b = sl.b; - de->file = f->addr; - changed(sl.b); - mbput(sl.b); - break; - } - mbput(sl.b); - } - changed(d); - noerror(); -} - -/* - * does not dbdecref(f) - * caller locks both d and f - */ -void -dfunlink(Memblk *d, Memblk *f) -{ - Dentry *de; - Child *c; - - dDprint("dfunlink\n %H %H\n", d, f); - iswlocked(d); - ismelted(d); - isdir(d); - if(d->mf->length > 0 && d->mf->child == nil) - dfloaddir(d, 1); - - c = getchild(d, f); - ismelted(c->b); - de = c->d; - de->file = 0; - changed(c->b); - mbput(c->b); - delchild(d, c); - changed(d); -} - -void -dfloaddir(Memblk *d, int locked) -{ - Blksl sl; - Dentry *de; - uvlong off; - Memblk *f; - Child *c; - - isdir(d); - if(d->mf->length == 0 || d->mf->child != nil) /* already loaded */ - return; - if(locked) - iswlocked(d); - else - wlock(d->mf); - if(catcherror()){ - wunlock(d->mf); - error(nil); - } - off = 0; - for(;;){ - sl = dfslice(d, sizeof(Dentry), off, 0); - if(sl.len == 0) - break; - off += sl.len; - if(sl.len < sizeof(Dentry)){ /* trailing part in block */ - mbput(sl.b); - continue; - } - if(catcherror()){ - mbput(sl.b); - error(nil); - } - de = sl.data; - if(de->file == 0) - continue; - f = dbget(DBfile, de->file); - c = addchild(d, f); - c->d = de; - c->b = sl.b; - mbput(f); - noerror(); - } - if(!locked) - wunlock(d->mf); - noerror(); -} - -/* - * Walk to a child and return it both referenced and locked. - * If iswr, d must not be frozen and the child is returned melted. - * caller locks d. - * dir must be already loaded. - */ -Memblk* -dfwalk(Memblk *d, char *name, int iswr) -{ - Memblk *f, *nf; - int i; - Mfile *m; - Child *c; - - dDprint("dfwalk '%s' at %H\n", name, d); - isdir(d); - if(iswr){ - iswlocked(d); - ismelted(d); - }else - isrlocked(d); - isloaded(d); - - m = d->mf; - for(i = 0; i < m->nchild; i++){ - c = &m->child[i]; - f = c->f; - if(strcmp(f->mf->name, name) == 0){ - if(iswr) - wlock(f->mf); - else - rlock(f->mf); - if(!iswr || !f->frozen){ - incref(f); - return(f); - } - /* hard: it's frozen and iswr; must melt it */ - nf = dbdup(f); - wunlock(f->mf); - wlock(nf->mf); - dbdecref(f->addr); - mbput(f); - c->f = nf; - incref(nf); - c->d->file = nf->addr; - changed(c->b); - ismelted(nf); - iswlocked(nf); - return nf; - } - } - error("file not found"); - return nil; -} - -/* - * Found a file b frozen, and need it to be melted. - * travel up the tree and walk down to b ensuring that it's melted. - * Return it wlocked, so nobody can freeze it again before we use it. - */ -Memblk* -dfmelt(Memblk *f) -{ - char **names; - int nnames; - Memblk *b, *pb, *nb; - - /* - * 1. travel up to a melted block or to the root, recording - * the names we will have to walk down to reach f. - */ - isfile(f); - rlock(f->mf); - names = nil; - nnames = 0; - for(b = f; b != nil; b = pb){ - if(b == fs->active || b == fs->archive) - break; - if(nnames%Incr == 0) - names = realloc(names, (nnames+Incr)*sizeof(char*)); - names[nnames++] = strdup(b->mf->name); - pb = b->mf->parent; - runlock(b->mf); - rlock(pb->mf); - } - runlock(b->mf); - - /* - * 2. walk down from active to f, ensuring everything is melted. - */ - for(;;){ - b = fs->active; - wlock(b->mf); - if(!b->frozen) - break; - wunlock(b->mf); - } - ismelted(b); - incref(b); - if(catcherror()){ - while(nnames-- > 0) - free(names[nnames]); - free(names); - wunlock(b->mf); - mbput(b); - error("can't melt: %r"); - } - - while(nnames-- > 0){ - if(b->mf->length > 0 && b->mf->child == nil) - dfloaddir(b, 1); - nb = dfwalk(b, names[--nnames], 1); - free(names[nnames]); - names[nnames] = nil; - wunlock(b->mf); - mbput(b); - b = nb; - USED(&b); /* flush b to memory for error()s */ - } - noerror(); - free(names); - iswlocked(b); - return b; -} - diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/file.c --- a/sys/src/cmd/Cfs/file.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,372 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "fns.h" - -/* - * Interface to handle files. - * see dk.h - */ - -/* - * Ok if nelems is 0. - */ -Memblk* -walkpath(Memblk *f, char *elems[], int nelems) -{ - int i; - Memblk *nf; - - isfile(f); - rlock(f->mf); - if(f->mf->length > 0 && f->mf->child == nil){ - runlock(f->mf); - dfloaddir(f, 0); - rlock(f->mf); - } - if(catcherror()){ - runlock(f->mf); - error(nil); - } - for(i = 0; i < nelems; i++){ - if((f->mf->mode&DMDIR) == 0) - error("not a directory"); - nf = dfwalk(f, elems[i], 0); - runlock(f->mf); - f = nf; - USED(&f); /* in case of error() */ - } - noerror(); - incref(f); - runlock(f->mf); - return f; -} - -Memblk* -dfcreate(Memblk *parent, char *name, char *uid, ulong mode) -{ - Memblk *b; - Mfile *m; - - dDprint("dfcreate '%s' %M at %H", name, mode, parent); - if(parent != nil){ - isdir(parent); - wlock(parent->mf); - if(parent->frozen){ - wunlock(parent->mf); - parent = dfmelt(parent); - }else - incref(parent); - b = dballoc(DBfile); - }else - b = dballoc(Noaddr); /* root */ - - if(catcherror()){ - wunlock(b->mf); - mbput(b); - if(parent != nil){ - wunlock(parent->mf); - mbput(parent); - } - error("create: %r"); - } - m = b->mf; - m->id = b->d.epoch; - m->mode = mode; - m->mtime = b->d.epoch; - m->length = 0; - m->uid = uid; - m->gid = uid; - m->muid = uid; - m->name = name; - b->d.asize = pmeta(b->d.embed, Embedsz, m); - - if(parent != nil){ - m->gid = parent->mf->uid; - dflink(parent, b); - wunlock(parent->mf); - mbput(parent); - } - noerror(); - changed(b); - dDprint("dfcreate-> %H\n", b); - return b; -} - -/* - * returns a slice into a block for reading. - */ -Blksl -dfreadblk(Memblk *f, ulong len, uvlong off) -{ - Blksl sl; - - dDprint("dfreadblk m%#p len %#ulx off %#ullx\n", f, len, off); - isfile(f); - rlock(f->mf); - if(catcherror()){ - runlock(f->mf); - error("read: %r"); - } - sl = dfslice(f, len, off, 0); - noerror(); - runlock(f->mf); - return sl; -} - -/* - * returns a slice into a block for writing - * the block is returned unlocked. - */ -Blksl -dfwriteblk(Memblk *f, ulong count, uvlong off) -{ - Blksl sl; - - dDprint("dfwriteblk m%#p off %#ullx\n", f, off); - isnotdir(f); - wlock(f->mf); - if(f->frozen){ - wunlock(f->mf); - f = dfmelt(f); - }else - incref(f); - if(catcherror()){ - wunlock(f->mf); - error(nil); - } - sl = dfslice(f, count, off, 1); - noerror(); - wunlock(f->mf); - mbput(f); - return sl; -} - -ulong -dfpread(Memblk *f, void *a, ulong count, uvlong off) -{ - Blksl sl; - ulong tot; - char *p; - - p = a; - for(tot = 0; tot < count; tot += sl.len){ - sl = dfreadblk(f, count-tot, off+tot); - if(sl.len == 0) - break; - if(sl.data == nil){ - memset(p+tot, 0, sl.len); - continue; - } - memmove(p+tot, sl.data, sl.len); - mbput(sl.b); - } - return tot; -} - -ulong -dfpwrite(Memblk *f, void *a, ulong count, uvlong off) -{ - Blksl sl; - ulong tot; - char *p; - - p = a; - for(tot = 0; tot < count; tot += sl.len){ - sl = dfwriteblk(f, count-tot, off+tot); - if(sl.len == 0 || sl.data == nil) - sysfatal("dfpwrite: bug"); - memmove(sl.data, p+tot, sl.len); - changed(sl.b); - mbput(sl.b); - } - return tot; -} - -/* - * Freezing should not fail. - * If it does, we can't even freeze the tree to sync to disk, - * so there's not much to do. - * The caller with probably catch the error and sysfatal. - */ - - -/* - * freeze a direct or indirect pointer and everything below it. - */ -static void -ptrfreeze(u64int addr, int nind) -{ - int i; - Memblk *b; - - if(addr == 0) - return; - b = mbget(addr); - if(b == nil) - return; /* on disk: frozen */ - if(!b->frozen){ - b->frozen = 1; - if(nind > 0) - for(i = 0; i < Dptrperblk; i++) - ptrfreeze(b->d.ptr[i], nind-1); - } - mbput(b); -} - -/* - * freeze a file. - * Do not recur if children is found frozen. - */ -void -dffreeze(Memblk *f) -{ - int i; - Memblk *b; - - iswlocked(f); - isfile(f); - dDprint("dffrezee m%#p\n", f); - f->frozen = 1; - for(i = 0; i < nelem(f->d.dptr); i++) - ptrfreeze(f->d.dptr[i], 0); - for(i = 0; i < nelem(f->d.iptr); i++) - ptrfreeze(f->d.dptr[i], i+1); - if((f->mf->mode&DMDIR) == 0) - return; - for(i = 0; i < f->mf->nchild; i++){ - b = f->mf->child[i].f; - if(!b->frozen){ - wlock(b->mf); - dffreeze(b); - wunlock(b->mf); - } - } -} - -/* - * freeze a direct or indirect pointer and everything below it. - */ -static void -ptrsync(u64int addr, int nind) -{ - int i; - Memblk *b; - - if(addr == 0) - return; - b = mbget(addr); - if(b == nil) - return; /* on disk */ - if(!b->frozen) - sysfatal("ptrsync: not frozen\n\t%H", b); - if(b->dirty) - dbwrite(b); - b->dirty = 0; - mbput(b); - if(nind > 0) - for(i = 0; i < Dptrperblk; i++) - ptrsync(b->d.ptr[i], nind-1); -} - -/* - * Ensure all frozen but dirty blocks are in disk. - */ -void -dfsync(Memblk *f) -{ - int i; - - isfile(f); - if(f->written) - return; - if(!f->frozen) - sysfatal("dfsync: not frozen\n\t%H", f); - - for(i = 0; i < nelem(f->d.dptr); i++) - ptrsync(f->d.dptr[i], 0); - for(i = 0; i < nelem(f->d.iptr); i++) - ptrsync(f->d.dptr[i], i+1); - for(i = 0; i < f->mf->nchild; i++) - dfsync(f->mf->child[i].f); - - rlock(f->mf); - if(f->dirty) - dbwrite(f); - f->dirty = 0; - f->written = 1; - runlock(f->mf); -} - -/* - * release a direct or indirect pointer and everything below it. - */ -static int -ptrreclaim(u64int addr, int nind) -{ - int i; - Memblk *b; - - if(addr == 0) - return 0; - if(dbdecref(addr) != 0) - return 0; - b = dbget(DBdata+nind, addr); - if(!b->frozen) - sysfatal("ptrreclaim: not frozen\n\t%H", b); - mbunhash(b); - if(b->ref != 1) - sysfatal("dfreclaim: bug?"); - if(nind > 0) - for(i = 0; i < Dptrperblk; i++) - ptrreclaim(b->d.ptr[i], nind-1); - mbput(b); - return 1; -} - -/* - * remove f and all it's children. - * It's safe to remove the parent before the children, - * because no reference to f is kept in the disk when this - * function is called. - * - * One problem here is that we have to load the blocks - * to actually learn their references and remove them. - * TODO: do this using an external cleaner program? - */ -int -dfreclaim(Memblk *f) -{ - int i, tot; - - tot = 0; - dDprint("dfreclaim %H", f); - if(dbdecref(f->addr) != 0) - return 0; - tot++; - if(!f->frozen) - sysfatal("dfsync: not frozen\n\t%H", f); - incref(f); - mbunhash(f); - if(f->ref != 1) - sysfatal("dfreclaim: ref is %d", f->ref); - for(i = 0; i < nelem(f->d.dptr); i++) - tot += ptrreclaim(f->d.dptr[i], 0); - for(i = 0; i < nelem(f->d.iptr); i++) - tot += ptrreclaim(f->d.dptr[i], i+1); - if(f->mf->mode&DMDIR){ - isloaded(f); - for(i = 0; i < f->mf->nchild; i++) - tot += dfreclaim(f->mf->child[i].f); - } - mbput(f); - return tot; -} - diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/fns.h --- a/sys/src/cmd/Cfs/fns.h Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -extern u64int addrofref(u64int refaddr, int idx); -extern void changed(Memblk *b); -extern void clean(Memblk *b); -extern Memblk* dballoc(uint type); -extern void dbclear(u64int addr, int type); -extern u64int dbdecref(u64int addr); -extern Memblk* dbdup(Memblk *b); -extern Memblk* dbget(uint type, u64int addr); -extern u64int dbgetref(u64int addr); -extern void dbincref(u64int addr); -extern long dbread(Memblk *b); -extern void dbsetref(u64int addr, u64int ref); -extern long dbwrite(Memblk *b); -extern void delchild(Memblk *d, Child *c); -extern Memblk* dfcreate(Memblk *parent, char *name, char *uid, ulong mode); -extern void dffreeze(Memblk *f); -extern void dflink(Memblk *d, Memblk *f); -extern void dfloaddir(Memblk *d, int locked); -extern Memblk* dfmelt(Memblk *f); -extern ulong dfpread(Memblk *f, void *a, ulong count, uvlong off); -extern ulong dfpwrite(Memblk *f, void *a, ulong count, uvlong off); -extern long dfrattr(Memblk *f, char *name, void *val, long count); -extern Blksl dfreadblk(Memblk *f, ulong len, uvlong off); -extern int dfreclaim(Memblk *f); -extern Blksl dfslice(Memblk *f, ulong len, uvlong off, int iswr); -extern void dfsync(Memblk *f); -extern void dfunlink(Memblk *d, Memblk *f); -extern Memblk* dfwalk(Memblk *d, char *name, int iswr); -extern long dfwattr(Memblk *f, char *name, void *val, long nval); -extern Blksl dfwriteblk(Memblk *f, ulong count, uvlong off); -extern void disktohost(Memblk *b); -extern ulong embedattrsz(Memblk *f); -extern void fsdump(void); -extern void fsfmt(char *dev); -extern Memblk* fsfreeze(void); -extern void fsopen(char *dev); -extern void fsreclaim(void); -extern void fssync(void); -extern void gmeta(Fmeta *meta, void *buf, ulong nbuf); -extern Memblk* hosttodisk(Memblk *b); -extern void isdir(Memblk *d); -extern int iserror(char *s); -extern void isfile(Memblk *d); -extern void isloaded(Memblk *d); -extern void ismelted(Memblk *b); -extern void isnotdir(Memblk *d); -extern void isrlocked(Memblk *b); -extern void iswlocked(Memblk *b); -extern void main(int argc, char *argv[]); -extern void main(int argc, char *argv[]); -extern void main(int, char *argv[]); -extern Memblk* mballoc(u64int addr); -extern Memblk* mbdup(Memblk *b); -extern int mbfmt(Fmt *fmt); -extern Memblk* mbget(u64int addr); -extern Memblk* mbhash(Memblk *b); -extern void mbput(Memblk *b); -extern void mbunhash(Memblk *b); -extern void meltedref(Memblk *rb); -extern u64int newblkaddr(void); -extern uvlong now(void); -extern void okaddr(u64int addr); -extern ulong pmeta(void *buf, ulong nbuf, Fmeta *meta); -extern u64int refaddr(u64int addr, int *idx); -extern Memblk* walkpath(Memblk *f, char *elems[], int nelems); diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/fscmd.c --- a/sys/src/cmd/Cfs/fscmd.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,351 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "fns.h" - -enum -{ - Nels = 64 -}; - -static char *fsdir; -static int verb; - -static char* -fsname(char *p) -{ - if(p[0] == '/') - return strdup(p); - if(fsdir) - return smprint("%s/%s", fsdir, p); - return strdup(p); -} - -static Memblk* -walkto(char *a, char **lastp) -{ - char *els[Nels], *path; - int nels; - Memblk *f; - - path = fsname(a); - nels = gettokens(path, els, Nels, "/"); - if(nels < 1){ - free(path); - error("invalid path"); - } - if(catcherror()){ - free(path); - error("walkpath: %r"); - } - if(lastp != nil){ - f = walkpath(fs->root, els, nels-1); - *lastp = a + strlen(a) - strlen(els[nels-1]); - }else - f = walkpath(fs->root, els, nels); - free(path); - noerror(); - if(verb) - print("walked to %H", f); - return f; -} - -static void -fscd(int, char *argv[]) -{ - free(fsdir); - fsdir = strdup(argv[1]); -} - -static void -fsput(int, char *argv[]) -{ - int fd; - char *fn; - Memblk *m, *f; - Dir *d; - char buf[4096]; - uvlong off; - long nw, nr; - - fd = open(argv[1], OREAD); - if(fd < 0){ - fprint(2, "%s: open: %r\n", argv[0]); - return; - } - d = dirfstat(fd); - if(d == nil){ - fprint(2, "%s: error: %r\n", argv[0]); - goto done; - } - if(catcherror()){ - fprint(2, "%s: error: %r\n", argv[0]); - goto done; - } - m = walkto(argv[2], &fn); - f = dfcreate(m, fn, d->uid, d->mode&(DMDIR|0777)); - if((d->mode&DMDIR) == 0){ - off = 0; - for(;;){ - nr = read(fd, buf, sizeof buf); - if(nr <= 0) - break; - nw = dfpwrite(f, buf, nr, off); - dDprint("wrote %ld of %ld bytes\n", nw, nr); - off += nr; - } - } - mbput(m); - if(verb) - print("created %H", f); - mbput(f); - noerror(); -done: - close(fd); - free(d); -} - -static void -fscat(int, char *argv[]) -{ - Memblk *f; - Mfile *m; - char buf[4096]; - uvlong off; - long nr; - - if(catcherror()){ - fprint(2, "%s: error: %r\n", argv[0]); - return; - } - f = walkto(argv[2], nil); - if(catcherror()){ - fprint(2, "%s: error: %r\n", argv[0]); - mbput(f); - return; - } - m = f->mf; - print("cat %-30s\t%M\t%5ulld\t%s %ulld refs\n", - m->name, (ulong)m->mode, m->length, m->uid, dbgetref(f->addr)); - if((m->mode&DMDIR) == 0){ - off = 0; - for(;;){ - nr = dfpread(f, buf, sizeof buf, off); - if(nr <= 0) - break; - write(1, buf, nr); - off += nr; - } - } - noerror(); - noerror(); - mbput(f); -} - -static void -fsget(int, char *argv[]) -{ - Memblk *f; - Mfile *m; - char buf[4096]; - uvlong off; - long nr; - int fd; - - fd = create(argv[1], OWRITE, 0664); - if(fd < 0){ - fprint(2, "%s: error: %r\n", argv[0]); - return; - } - if(catcherror()){ - close(fd); - fprint(2, "%s: error: %r\n", argv[0]); - return; - } - f = walkto(argv[2], nil); - if(catcherror()){ - mbput(f); - error(nil); - } - m = f->mf; - print("get %-30s\t%M\t%5ulld\t%s %ulld refs\n", - m->name, (ulong)m->mode, m->length, m->uid, dbgetref(f->addr)); -print("%H", f); - if((m->mode&DMDIR) == 0){ - off = 0; - for(;;){ - nr = dfpread(f, buf, sizeof buf, off); - if(nr <= 0) - break; - if(write(fd, buf, nr) != nr){ - fprint(2, "%s: error: %r\n", argv[0]); - break; - } - off += nr; - } - } - close(fd); - noerror(); - noerror(); - mbput(f); -} - -static void -flist(Memblk *f, char *ppath) -{ - char *path; - Mfile *m; - int i; - - m = f->mf; - if(m->mode&DMDIR) - dfloaddir(f, 0); - rlock(m); - if(ppath == nil){ - print("/"); - path = strdup(m->name); - }else - path = smprint("%s/%s", ppath, m->name); - print("%-30s\t%M\t%5ulld\t%s %ulld refs\n", - path, (ulong)m->mode, m->length, m->uid, dbgetref(f->addr)); - if(m->mode&DMDIR) - for(i = 0; i < m->nchild; i++) - flist(m->child[i].f, path); - runlock(m); - free(path); -} - -static void -fslist(int, char**) -{ - u64int msz, fact; - int i; - - msz = Embedsz - Dminattrsz + Ndptr*Dblkdatasz; - fact = Dblkdatasz; - for(i = 0; i < Niptr; i++){ - msz += Dptrperblk * fact; - fact *= Dptrperblk; - } - print("fsys '%s' blksz %ulld maxdfsz %ulld:\n", - fs->dev, fs->super->d.dblksz, msz); - if(verb) - fsdump(); - else - flist(fs->root, nil); - print("\n"); -} - -static void -fssnap(int, char**) -{ - fssync(); -} - -static void -fsrcl(int, char**) -{ - fsreclaim(); -} - -static void -usage(void) -{ - fprint(2, "usage: %s [-DFLAGS] [-dv] [-f disk] cmd...\n", argv0); - exits("usage"); -} - -static struct -{ - char *name; - void (*f)(int, char**); - int nargs; - char *usage; -} cmds[] = -{ - {"cd", fscd, 2, "cd!where"}, - {"put", fsput, 3, "put!src!dst"}, - {"get", fsget, 3, "get!dst!src"}, - {"cat", fscat, 3, "cat!what"}, - {"ls", fslist, 1, "ls"}, - {"snap", fssnap, 1, "snap"}, - {"rcl", fsrcl, 1, "rcl"}, -}; - -static char xdbg[256]; -static char zdbg[256]; - -void -main(int argc, char *argv[]) -{ - char *dev; - char *args[Nels]; - int i, j, nargs; - - dev = "disk"; - ARGBEGIN{ - case 'v': - verb++; - break; - case 'f': - dev = EARGF(usage()); - break; - default: - if(ARGC() >= 'A' && ARGC() <= 'Z'){ - xdbg['d'] = 1; - xdbg[ARGC()] = 1; - }else - usage(); - }ARGEND; - if(argc == 0) - usage(); - fmtinstall('H', mbfmt); - fmtinstall('M', dirmodefmt); - errinit(Errstack); - if(catcherror()) - sysfatal("error: %r"); - fsopen(dev); - for(i = 0; i < argc; i++){ - if(catcherror()) - sysfatal("cmd %s: %r", argv[i]); - if(verb>1) - fsdump(); - else if(verb) - flist(fs->root, nil); - print("%% %s\n", argv[i]); - nargs = gettokens(argv[i], args, Nels, "!"); - for(j = 0; j < nelem(cmds); j++){ - if(strcmp(cmds[j].name, argv[i]) != 0) - continue; - if(cmds[j].nargs != 0 && cmds[j].nargs != nargs) - print("usage: %s\n", cmds[j].usage); - else{ - memmove(dbg, xdbg, sizeof xdbg); - cmds[j].f(nargs, args); - memmove(dbg, zdbg, sizeof zdbg); - } - break; - } - noerror(); - if(j == nelem(cmds)){ - print("no such command\n"); - for(j = 0; j < nelem(cmds); j++) - print("\t%s\n", cmds[j].usage); - break; - } - } - if(verb>1) - fsdump(); - else if(verb) - flist(fs->root, nil); - noerror(); - exits(nil); -} - diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/fsfmt.c --- a/sys/src/cmd/Cfs/fsfmt.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "fns.h" - -static void -usage(void) -{ - fprint(2, "usage: %s [-DFLAGS] [-dv]\n", argv0); - exits("usage"); -} - -void -main(int argc, char *argv[]) -{ - int verb; - char *dev; - - dev = "disk"; - verb = 0; - ARGBEGIN{ - case 'v': - verb++; - break; - default: - if(ARGC() >= 'A' && ARGC() <= 'Z'){ - dbg['d'] = 1; - dbg[ARGC()] = 1; - }else - usage(); - }ARGEND; - if(argc == 1) - dev = argv[0]; - else if(argc > 0) - usage(); - fmtinstall('H', mbfmt); - fmtinstall('M', dirmodefmt); - errinit(Errstack); - if(catcherror()) - sysfatal("error: %r"); - fsfmt(dev); - if(verb) - fsdump(); - noerror(); - exits(nil); -} - diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/fsys.c --- a/sys/src/cmd/Cfs/fsys.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,451 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "fns.h" - -Fsys *fs; - -/* - * All the code assumes outofmemoryexits = 1. - */ - -int -iserror(char *s) -{ - char err[128]; - - rerrstr(err, sizeof err); - return strstr(err, s) != nil; -} - -uvlong -now(void) -{ - return nsec(); -} - -void -okaddr(u64int addr) -{ - if(addr < Dblksz || addr >= fs->limit) - error("okaddr %#ullx", addr); -} - -/* - * NO LOCKS. debug only - */ -void -fsdump(void) -{ - int i, flg; - Memblk *b; - u64int a; - - if(fs != nil){ - print("\n\nfsys '%s' limit %#ulx super m%#p root m%#p:\n", - fs->dev, fs->limit, fs->super, fs->root); - for(i = 0; i < nelem(fs->fhash); i++) - for(b = fs->fhash[i].b; b != nil; b = b->next) - print("h[%d] = %H", i, b); - print("nblk %uld nablk %uld used %uld free %uld\n", - fs->nblk, fs->nablk, fs->nused, fs->nfree); - } - b = fs->super; - if(b->d.free != 0){ - print("free:"); - flg = dbg['D']; - dbg['D'] = 0; - for(a = b->d.free; a != 0; a = dbgetref(a)) - print(" d%#ullx", a); - dbg['D'] = flg; - print("\n"); - } - print("Fsysmem\t= %uld\n", Fsysmem); - print("Dminfree\t= %d\n", Dminfree); - print("Dblksz\t= %uld\n", Dblksz); - print("Dminattrsz\t= %uld\n", Dminattrsz); - print("Nblkgrpsz\t= %uld\n", Nblkgrpsz); - print("Dblkdatasz\t= %d\n", Dblkdatasz); - print("Embedsz\t= %d\n", Embedsz); - print("Dentryperblk\t= %d\n", Dentryperblk); - print("Dptrperblk\t= %d\n\n", Dptrperblk); -} - -static usize -disksize(int fd) -{ - Dir *d; - u64int sz; - - d = dirfstat(fd); - if(d == nil) - return 0; - sz = d->length; - free(d); - return sz; -} - -static void -freezerefs(void) -{ - Memblk *rb; - - qlock(fs); - for(rb = fs->refs; rb != nil; rb = rb->next) - rb->frozen = 1; - qunlock(fs); -} - -static void -writerefs(void) -{ - Memblk *rb; - - qlock(fs); - for(rb = fs->refs; rb != nil; rb = rb->next) - meltedref(rb); - qunlock(fs); -} - -static void -freezesuper(void) -{ - Memblk *b; - - b = mbdup(fs->super); - qlock(fs); - b->d = fs->super->d; - assert(fs->fzsuper == nil); - fs->fzsuper = b; - fs->fzsuper->frozen = 1; - qunlock(fs); -} - -static void -writesuper(void) -{ - qlock(fs); - assert(fs->fzsuper != nil); - qunlock(fs); - dbwrite(fs->fzsuper); - dDprint("fswrite: %H", fs->fzsuper); - mbput(fs->fzsuper); - fs->fzsuper = nil; -} - -/* - * Write any dirty frozen state after a freeze. - * Only this function and initialization of previously unused DBref - * blocks may write to the disk. - */ -static void -fswrite(void) -{ - if(fs->fzsuper == nil) - sysfatal("can't fswrite if we didn't fsfreeze"); - writerefs(); - dfsync(fs->archive); - writesuper(); -} - -/* - * 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. - */ -Memblk* -fsfreeze(void) -{ - Memblk *na, *oa, *arch, *super; - Child *ac; - char name[50]; - int i; - - wlock(fs->active->mf); - wlock(fs->archive->mf); - if(fs->fzsuper != nil){ - wunlock(fs->archive->mf); - wunlock(fs->active->mf); - error("freeze already in progress"); - } - dfloaddir(fs->active, 1); - dfloaddir(fs->archive, 1); - super = fs->super; - if(catcherror()){ - /* - * Freeze can't fail. If it does, we better - * restart the file system from the last known - * frozen tree. - * The only reasing this should happen is because - * we run out of memory, or out of disk, or - * the disk fails. - */ - sysfatal("freeze: can't recover: %r"); - } - - /* - * move active into /archive/ and create a new melted - * active. - */ - oa = fs->active; - na = dbdup(oa); - wlock(na->mf); - seprint(name, name+sizeof(name), "%ulld", oa->d.epoch); - dfwattr(oa, "name", name, strlen(name)+1); - ac = fs->root->mf->child; - assert(ac->f == oa); - ac->f = na; /* keeps the ref we have */ - ac->d->file = na->addr; - if(fs->archive->frozen){ - arch = dbdup(fs->archive); - wlock(arch->mf); - wunlock(fs->archive->mf); - mbput(fs->archive); - fs->archive = arch; - for(i = nelem(super->d.root)-1; i > 0; i--) - super->d.root[i] = super->d.root[i-1]; - super->d.root[0] = fs->archive->addr; - } - dflink(fs->archive, oa); - fs->active = na; - fs->archive->frozen = 1; /* for fsfmt */ - - /* 1. Free the entire previously active - */ - dffreeze(oa); - wunlock(oa->mf); - - /* 2. Freeze whatever new blocks are found in archive - */ - dffreeze(fs->archive); - - /* 3. Freeze the on-disk reference counters - * and the state of the super-block. - */ - freezerefs(); - freezesuper(); - - /* - /* 4. release locks, all done. - */ - wunlock(na->mf); - wunlock(fs->archive->mf); - noerror(); - return na; -} - -static void -fsinit(char *dev, int nblk) -{ - fs = mallocz(sizeof *fs, 1); - fs->dev = strdup(dev); - fs->fd = open(dev, ORDWR); - if(fs->fd < 0) - sysfatal("can't open disk: %r"); - - fs->nablk = Fsysmem / sizeof(Memblk); - if(nblk > 0 && nblk < fs->nablk) - fs->nablk = nblk; - fs->limit = disksize(fs->fd); - if(fs->nablk > fs->limit/Dblksz) - fs->nablk = fs->limit/Dblksz; - fs->limit = fs->nablk * Dblksz; - if(fs->limit < 10*Dblksz) - sysfatal("disk is ridiculous"); - fs->blk = malloc(fs->nablk * sizeof fs->blk[0]); - dDprint("fsys '%s' init\n", fs->dev); -} - -/* - * / is only in memory. It's `on-disk' address is Noaddr. - * - * /archive is the root on disk. - * /active is allocated on disk, but not on disk. It will be linked into - * /archive as a child in the future. - */ -void -fsfmt(char *dev) -{ - Memblk *super; - - if(catcherror()) - sysfatal("fsfmt: error: %r"); - - fsinit(dev, 16); /* enough # of blocks for fmt */ - - fs->super = dballoc(DBsuper); - super = fs->super; - super->d.eaddr = fs->super->addr + Dblksz; - super->d.dblksz = Dblksz; - super->d.nblkgrpsz = Nblkgrpsz; - super->d.dminattrsz = Dminattrsz; - - fs->root = dfcreate(nil, "", getuser(), DMDIR|0555); - fs->active = dfcreate(fs->root, "active", getuser(), DMDIR|0775); - fs->archive = dfcreate(fs->root, "archive", getuser(), DMDIR|0555); - super->d.root[0] = fs->archive->addr; - - fsfreeze(); - fswrite(); - - noerror(); -} - -void -fssync(void) -{ - /* - * TODO: If active has not changed and we are just going - * to dump a new archive for no change, do nothing. - */ - fsfreeze(); - fswrite(); -} - -static Memblk* -readsuper(void) -{ - Memblk *super; - - fs->super = dbget(DBsuper, Dblksz); - super = fs->super; - if(super->d.dblksz != Dblksz) - error("bad Dblksz"); - if(super->d.nblkgrpsz != Nblkgrpsz) - error("bad Nblkgrpsz"); - if(super->d.dminattrsz != Dminattrsz) - error("bad Dminattrsz"); - return super; -} - -/* - * One process per file system, so consume all the memory - * for the cache. - * To open more file systems, use more processes! - */ - -void -fsopen(char *dev) -{ - if(catcherror()) - sysfatal("fsopen: error: %r"); - - fsinit(dev, 0); - - readsuper(); - - fs->root = dfcreate(nil, "", getuser(), DMDIR|0555); - fs->active = dfcreate(fs->root, "active", getuser(), DMDIR|0775); - fs->archive = dbget(DBfile, fs->super->d.root[0]); - wlock(fs->root->mf); - wlock(fs->archive->mf); - dflink(fs->root, fs->archive); - wunlock(fs->archive->mf); - wunlock(fs->root->mf); - noerror(); -} - -/* - * XXX: must revisit here: - * - there are several things been done multiple times in different - * functions. e.g., writing the super, compare - * fsfmt and fsopen - * fsreclaim and fsfreeze. - * some inner functions are missing there. - * - * - it's not clear references end up ok after fsreclaim, must test that. - * - perhaps we should reclaim in a loop until we are sure that - * at least a min # of blocks are available or we can't reclaim anything else, - * whatever happens first. - * - * - must implement a variant of the fsfmt function that reads an archived - * tree and formats the file system according to it. Although that's - * perhaps just a fsfmt() followed by the inverse o fthe archival tool, - * and we may leave fsfmt alone. - */ - -/* - * This should be called if fs->super->d.nfree < some number. - */ -void -fsreclaim(void) -{ - uvlong nfree; - Child *c, *victim; - Memblk *arch, *gone; - int i, n, tot; - - tot = 0; - for(;;){ - qlock(fs); - nfree = fs->super->d.nfree; - nfree += (fs->limit - fs->super->d.eaddr)/Dblksz; - qunlock(fs); - if(nfree > Dminfree){ - dDprint("fsreclaim: got %ulld free\n", nfree); - break; - } - dDprint("fsreclaim: reclaiming: %ulld free\n", nfree); - arch = fs->archive; - wlock(arch->mf); - dfloaddir(arch, 1); - if(arch->mf->nchild < 2){ - wunlock(arch->mf); - dDprint("nothing to reclaim\n"); - break; - } - victim = arch->mf->child; - for(i = 0; i < arch->mf->nchild; i++){ - c = &arch->mf->child[i]; - if(victim->f->d.epoch > c->f->d.epoch) - victim = c; - } - - gone = victim->f; - fprint(2, "%s: reclaiming /archive/%s\n", argv0, gone->mf->name); - dDprint("victim is %H", gone); - - /* - * Surgery: we don't want to allocate anything by now. - * Just clear the references on disk and memory to the victim. - * If we fail before finishing then RCs will be >= the - * value they should have (the reference is gone from disk). - */ - victim->d->file = 0; - dbwrite(victim->b); - delchild(arch, victim); - wunlock(arch->mf); - - n = dbgetref(gone->addr); - if(n != 1) - sysfatal("reclaim: gone ref is %d != 1", n); - n = dfreclaim(gone); - dDprint("%d block%s reclaimed\n", n, n?"s":""); - tot += n; - - /* - * Hopefully we have some free blocks. - * dump the reference blocks to disk. - * Gone blocks are in the free list, active blocks may end up - * with on-disk refs >= those matching the references on disk, - * the next snap will make the ref list coherent. - * We don't snap here because that is likely to allocate more - * blocks. - */ - freezerefs(); - writerefs(); - freezesuper(); - dDprint("fsreclaim: %H", fs->fzsuper); - writesuper(); - } - if(tot > 0) - fprint(2, "%s: %d block%s reclaimed\n", argv0, tot, tot?"s":""); - -} diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/main.c --- a/sys/src/cmd/Cfs/main.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "fns.h" - -void -main(int, char *argv[]) -{ - argv0 = argv[0]; - fmtinstall('H', mbfmt); - fmtinstall('M', dirmodefmt); - errinit(Errstack); - if(catcherror()) - sysfatal("error: %r"); - fsopen("disk"); - fsdump(); - dbg['D'] = 1; - fsreclaim(); - fsdump(); - noerror(); - exits(nil); -} - diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/mblk.c --- a/sys/src/cmd/Cfs/mblk.c Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,348 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "dbg.h" -#include "dk.h" -#include "fns.h" - -/* - * memory blocks. - * see dk.h - */ - - -/* - * All the code assumes outofmemoryexits = 1. - */ - -char*tname[] = { -[DBfree] "free", -[DBsuper] "super", -[DBref] "ref", -[DBdata] "data", -[DBattr] "attr", -[DBfile] "file", -[DBptr0] "ptr0", -[DBptr0+1] "ptr1", -[DBptr0+2] "ptr2", -[DBptr0+3] "ptr3", -[DBptr0+4] "ptr4", -[DBptr0+5] "ptr5", -[DBptr0+6] "ptr6", -}; - -#define EP(e) ((e)&0xFFFFFFFFUL) -/* - * NO LOCKS. debug only - */ -static void -fmttab(Fmt *fmt, int t) -{ - if(t-- > 0) - fmtprint(fmt, "\t"); - while(t-- > 0) - fmtprint(fmt, " "); -} -static int mbtab; -static void -fmtptr(Fmt *fmt, u64int addr, char *tag, int n) -{ - Memblk *b; - - if(addr == 0) - return; - b = mbget(addr); - if(b == nil){ - fmttab(fmt, mbtab); - fmtprint(fmt, "%s[%d] = d%#ullx \n", tag, n, addr); - }else{ - decref(b); - fmtprint(fmt, "%H", b); - } -} - -int -mbfmt(Fmt *fmt) -{ - Memblk *b; - int type, i, n, once, xdbg; - - b = va_arg(fmt->args, Memblk*); - if(b == nil) - return fmtprint(fmt, "\n"); - type = TAGTYPE(b->d.tag); - fmttab(fmt, mbtab); - mbtab++; - xdbg = dbg['D']; - dbg['D'] = 0; - fmtprint(fmt, "m%#p d%#ullx", b, b->addr); - if(b->frozen) - fmtprint(fmt, " FZ"); - if(b->dirty) - fmtprint(fmt, " DT"); - if(b->written) - fmtprint(fmt, " WR"); - fmtprint(fmt, " DB%s r%d", tname[type], b->ref); - fmtprint(fmt, " tag %#ullx epoch %#ullx", EP(b->d.tag), EP(b->d.epoch)); - switch(type){ - case DBfree: - case DBdata: - case DBattr: - fmtprint(fmt, "\n"); - break; - case DBref: - fmtprint(fmt, " rnext m%#p\n", b->rnext); - for(i = n = 0; i < Drefperblk; i++) - if(b->d.ref[i]){ - fmtprint(fmt, "\t[%d]d%#ullx=%#ullx", - i, addrofref(b->addr, i), b->d.ref[i]); - if(++n%5 == 0){ - fmtprint(fmt, "\n"); - if(i < Dptrperblk-1) - fmttab(fmt, mbtab); - } - } - if(n%5 != 0) - fmtprint(fmt, "\n"); - break; - case DBfile: - fmtprint(fmt, "\n"); - fmttab(fmt, mbtab); - fmtprint(fmt, "asz %#ullx aptr %#ullx\n", b->d.asize,b->d.aptr); - if(b->mf == nil){ - fmtprint(fmt, "no mfile\n"); - break; - } - fmttab(fmt, mbtab); - fmtprint(fmt, "id %#ullx mode %M mt %#ullx sz %#ullx '%s' '%s'\n", - EP(b->mf->id), (ulong)b->mf->mode, EP(b->mf->mtime), - b->mf->length, b->mf->uid, b->mf->name); - fmttab(fmt, mbtab); - fmtprint(fmt, "parent m%#p nr%d nw%d lastb m%#p lastbno %uld\n", - b->mf->parent, b->mf->readers, b->mf->writer, - b->mf->lastb, b->mf->lastbno); - if(b->mf->nchild > 0){ - fmttab(fmt, mbtab); - fmtprint(fmt, "child:"); - for(i = 0; i < b->mf->nchild; i++) - fmtprint(fmt, " m%#p", b->mf->child[i].f); - fmtprint(fmt, "\n"); - } - for(i = 0; i < nelem(b->d.dptr); i++) - fmtptr(fmt, b->d.dptr[i], "d", i); - for(i = 0; i < nelem(b->d.iptr); i++) - fmtptr(fmt, b->d.iptr[i], "i", i); - break; - case DBsuper: - fmttab(fmt, mbtab); - fmtprint(fmt, "free d%#ullx eaddr %#ullx root [", - b->d.free, b->d.eaddr); - once = 0; - for(i = 0; i < nelem(b->d.root); i++) - if(b->d.root[i] != 0){ - if(once++ != 0) - fmtprint(fmt, " "); - fmtprint(fmt, "d%#ullx", b->d.root[i]); - } - fmtprint(fmt, "]\n"); - break; - default: - if(type < DBptr0 || type >= DBptr0+Niptr){ - fmtprint(fmt, "", type); - break; - } - fmtprint(fmt, "\n"); - for(i = 0; i < Dptrperblk; i++) - fmtptr(fmt, b->d.ptr[i], "p", i); - break; - } - dbg['D'] = xdbg; - mbtab--; - return 0; -} - -void -clean(Memblk *b) -{ - b->dirty = 0; -} - -void -ismelted(Memblk *b) -{ - if(b->frozen) - sysfatal("frozen at pc %#p", getcallerpc(&b)); -} - -void -changed(Memblk *b) -{ - if(TAGTYPE(b->d.tag) != DBsuper) - ismelted(b); - b->d.epoch = now(); - b->dirty = 1; -} - -Memblk* -mbhash(Memblk *b) -{ - Memblk **h; - uint hv; - - hv = b->addr%nelem(fs->fhash); - wlock(&fs->fhash[hv]); - fs->nused++; - for(h = &fs->fhash[hv].b; *h != nil; h = &(*h)->next) - if((*h)->addr == b->addr){ - /* concurrent reads, use the first one */ - mbput(b); - b = *h; - goto Found; - } - *h = b; - if(b->next != nil) - sysfatal("mbhash: next"); - if(TAGTYPE(b->d.tag) == DBref){ - qlock(fs); - b->rnext = fs->refs; - fs->refs = b; - qunlock(fs); - } -Found: - incref(b); - wunlock(&fs->fhash[hv]); - return b; -} - -static void -mbfree(Memblk *b) -{ - Mfile *mf; - - if(b == nil) - return; - dDprint("mbfree %H\n", b); - if(b->ref > 0) - sysfatal("mbfree: has refs"); - if(b->next != nil) - sysfatal("mbfree: has next"); - if(TAGTYPE(b->d.tag) == DBref) - sysfatal("mbfree: is DBref"); - - if(TAGTYPE(b->d.tag) == DBfile && b->mf != nil){ - mf = b->mf; - b->mf = nil; - mf->nchild = 0; - if(mf->lastb != nil) - mbput(mf->lastb); - mf->lastb = nil; - mf->lastbno = 0; - mf->parent = nil; - mf->next = nil; - assert(mf->readers == mf->writer && mf->readers == 0); - qlock(fs); - mf->next = fs->mfree; - fs->mfree = mf; - qunlock(fs); - } - b->d.tag = DBfree; - b->frozen = b->written = b->dirty = 0; - b->addr = 0; - - qlock(fs); - fs->nfree++; - b->next = fs->free; - fs->free = b; - qunlock(fs); -} - -void -mbunhash(Memblk *b) -{ - Memblk **h; - uint hv; - - if(TAGTYPE(b->d.tag) == DBref) - sysfatal("mbunhash: DBref"); - - hv = b->addr%nelem(fs->fhash); - wlock(&fs->fhash[hv]); - for(h = &fs->fhash[hv].b; *h != nil; h = &(*h)->next) - if((*h)->addr == b->addr){ - if(*h != b) - sysfatal("mbunhash: dup block"); - *h = b->next; - b->next = nil; - fs->nused--; - wunlock(&fs->fhash[hv]); - mbput(b); - return; - } - sysfatal("mbunhash: not found"); -} - -Memblk* -mballoc(u64int addr) -{ - Memblk *b; - - b = nil; - qlock(fs); - if(fs->nblk < fs->nablk) - b = &fs->blk[fs->nblk++]; - else if(fs->free != nil){ - b = fs->free; - fs->free = b->next; - fs->nfree--; - }else{ - qunlock(fs); - error("evict block not implemented"); - } - qunlock(fs); - memset(b, 0, sizeof *b); - b->addr = addr; - b->ref = 1; - dDprint("mballoc %#ullx -> %H", addr, b); - return b; -} - -Memblk* -mbget(u64int addr) -{ - Memblk *b; - uint hv; - - hv = addr%nelem(fs->fhash); - rlock(&fs->fhash[hv]); - for(b = fs->fhash[hv].b; b != nil; b = b->next) - if(b->addr == addr){ - incref(b); - break; - } - runlock(&fs->fhash[hv]); - dDprint("mbget %#ullx -> m%#p\n", addr, b); - return b; -} - -void -mbput(Memblk *b) -{ - dDprint("mbput m%#p pc=%#p\n", b, getcallerpc(&b)); - if(decref(b) == 0) - mbfree(b); -} - -Memblk* -mbdup(Memblk *b) -{ - Memblk *nb; - - nb = mballoc(b->addr); - memmove(&nb->d, &b->d, sizeof b->d); - return nb; -} diff -r 9d88846ae23b -r 877e1ea171e2 sys/src/cmd/Cfs/mkfile --- a/sys/src/cmd/Cfs/mkfile Fri Feb 24 16:16:29 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -fns.h