diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/cwfs/dentry.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cwfs/dentry.c')
-rwxr-xr-x | sys/src/cmd/cwfs/dentry.c | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/sys/src/cmd/cwfs/dentry.c b/sys/src/cmd/cwfs/dentry.c new file mode 100755 index 000000000..35f6a38aa --- /dev/null +++ b/sys/src/cmd/cwfs/dentry.c @@ -0,0 +1,337 @@ +#include "all.h" + +Dentry* +getdir(Iobuf *p, int slot) +{ + if(!p) + return 0; + return (Dentry*)p->iobuf + slot%DIRPERBUF; +} + +void +accessdir(Iobuf *p, Dentry *d, int f, int uid) +{ + Timet t; + + if(p && p->dev->type != Devro) { + p->flags |= Bmod; + t = time(nil); + if(f & (FREAD|FWRITE)) + d->atime = t; + if(f & FWRITE) { + d->mtime = t; + d->muid = uid; + d->qid.version++; + } + } +} + +void +preread(Device *d, Off addr) +{ + Rabuf *rb; + + if(addr == 0) + return; + if(raheadq->count+10 >= raheadq->size) /* ugly knowing layout */ + return; + lock(&rabuflock); + rb = rabuffree; + if(rb == 0) { + unlock(&rabuflock); + return; + } + rabuffree = rb->link; + unlock(&rabuflock); + rb->dev = d; + rb->addr = addr; + fs_send(raheadq, rb); +} + +Off +rel2abs(Iobuf *p, Dentry *d, Off a, int tag, int putb, int uid) +{ + int i; + Off addr, qpath, indaddrs = 1, div; + Device *dev; + + if(a < 0) { + print("rel2abs: neg offset\n"); + if(putb) + putbuf(p); + return 0; + } + dev = p->dev; + qpath = d->qid.path; + + /* is `a' a direct block? */ + if(a < NDBLOCK) { + addr = d->dblock[a]; + if(!addr && tag) { + addr = bufalloc(dev, tag, qpath, uid); + d->dblock[a] = addr; + p->flags |= Bmod|Bimm; + } + if(putb) + putbuf(p); + return addr; + } + a -= NDBLOCK; + + /* + * loop through indirect block depths. + */ + for (i = 0; i < NIBLOCK; i++) { + indaddrs *= INDPERBUF; + /* is a's disk addr in this indir block or one of its kids? */ + if (a < indaddrs) { + addr = d->iblocks[i]; + if(!addr && tag) { + addr = bufalloc(dev, Tind1+i, qpath, uid); + d->iblocks[i] = addr; + p->flags |= Bmod|Bimm; + } + if(putb) + putbuf(p); + + div = indaddrs; + for (; i >= 0; i--) { + div /= INDPERBUF; + if (div <= 0) + panic("rel2abs: non-positive divisor"); + addr = indfetch(dev, qpath, addr, + (a/div)%INDPERBUF, Tind1+i, + (i == 0? tag: Tind1+i-1), uid); + } + return addr; + } + a -= indaddrs; + } + if(putb) + putbuf(p); + + /* quintuple-indirect blocks not implemented. */ + print("rel2abs: no %d-deep indirect\n", NIBLOCK+1); + return 0; +} + +/* + * read-ahead strategy + * on second block, read RAGAP blocks, + * thereafter, read RAGAP ahead of current pos + */ +Off +dbufread(Iobuf *p, Dentry *d, Off a, Off ra, int uid) +{ + Off addr; + + if(a == 0) + return 1; + if(a == 1 && ra == 1) { + while(ra < a+RAGAP) { + ra++; + addr = rel2abs(p, d, ra, 0, 0, uid); + if(!addr) + return 0; + preread(p->dev, addr); + } + return ra+1; + } + if(ra == a+RAGAP) { + addr = rel2abs(p, d, ra, 0, 0, uid); + if(!addr) + return 0; + preread(p->dev, addr); + return ra+1; + } + return ra; +} + +Iobuf* +dnodebuf(Iobuf *p, Dentry *d, Off a, int tag, int uid) +{ + Off addr; + + addr = rel2abs(p, d, a, tag, 0, uid); + if(addr) + return getbuf(p->dev, addr, Brd); + return 0; +} + +/* + * same as dnodebuf but it calls putbuf(p) + * to reduce interference. + */ +Iobuf* +dnodebuf1(Iobuf *p, Dentry *d, Off a, int tag, int uid) +{ + Off addr; + Device *dev; + + dev = p->dev; + addr = rel2abs(p, d, a, tag, 1, uid); + if(addr) + return getbuf(dev, addr, Brd); + return 0; + +} + +Off +indfetch(Device* d, Off qpath, Off addr, Off a, int itag, int tag, int uid) +{ + Iobuf *bp; + + if(!addr) + return 0; + bp = getbuf(d, addr, Brd); + if(!bp || checktag(bp, itag, qpath)) { + if(!bp) { + print("ind fetch bp = 0\n"); + return 0; + } + print("ind fetch tag\n"); + putbuf(bp); + return 0; + } + addr = ((Off *)bp->iobuf)[a]; + if(!addr && tag) { + addr = bufalloc(d, tag, qpath, uid); + if(addr) { + ((Off *)bp->iobuf)[a] = addr; + bp->flags |= Bmod; + if(tag == Tdir) + bp->flags |= Bimm; + settag(bp, itag, qpath); + } + } + putbuf(bp); + return addr; +} + +/* return INDPERBUF^exp */ +Off +ibbpow(int exp) +{ + static Off pows[] = { + 1, + INDPERBUF, + (Off)INDPERBUF*INDPERBUF, + (Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF, + (Off)INDPERBUF*(Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF, + }; + + if (exp < 0) + return 0; + else if (exp >= nelem(pows)) { /* not in table? do it long-hand */ + Off indpow = 1; + + while (exp-- > 0 && indpow > 0) + indpow *= INDPERBUF; + return indpow; + } else + return pows[exp]; +} + +/* return sum of INDPERBUF^n for 1 ≤ n ≤ exp */ +Off +ibbpowsum(int exp) +{ + Off indsum = 0; + + for (; exp > 0; exp--) + indsum += ibbpow(exp); + return indsum; +} + +/* zero bytes past new file length; return an error code */ +int +trunczero(Truncstate *ts) +{ + int blkoff = ts->newsize % BUFSIZE; + Iobuf *pd; + + pd = dnodebuf(ts->p, ts->d, ts->lastblk, Tfile, ts->uid); + if (pd == nil || checktag(pd, Tfile, QPNONE)) { + if (pd != nil) + putbuf(pd); + ts->err = Ephase; + return Ephase; + } + memset(pd->iobuf+blkoff, 0, BUFSIZE - blkoff); + putbuf(pd); + return 0; +} + +/* + * truncate d (in p) to length `newsize'. + * if larger, just increase size. + * if smaller, deallocate blocks after last one + * still in file at new size. last byte to keep + * is newsize-1, due to zero origin. + * we free in forward order because it's simpler to get right. + * if the final block at the new size is partially-filled, + * zero the remainder. + */ +int +dtrunclen(Iobuf *p, Dentry *d, Off newsize, int uid) +{ + int i, pastlast; + Truncstate trunc; + + if (newsize <= 0) { + dtrunc(p, d, uid); + return 0; + } + memset(&trunc, 0, sizeof trunc); + trunc.d = d; + trunc.p = p; + trunc.uid = uid; + trunc.newsize = newsize; + trunc.lastblk = newsize/BUFSIZE; + if (newsize % BUFSIZE == 0) + trunc.lastblk--; + else + trunczero(&trunc); + for (i = 0; i < NDBLOCK; i++) + if (trunc.pastlast) { + trunc.relblk = i; + buffree(p->dev, d->dblock[i], 0, &trunc); + d->dblock[i] = 0; + } else if (i == trunc.lastblk) + trunc.pastlast = 1; + trunc.relblk = NDBLOCK; + for (i = 0; i < NIBLOCK; i++) { + pastlast = trunc.pastlast; + buffree(p->dev, d->iblocks[i], i+1, &trunc); + if (pastlast) + d->iblocks[i] = 0; + } + + d->size = newsize; + p->flags |= Bmod|Bimm; + accessdir(p, d, FWRITE, uid); + return trunc.err; +} + +/* + * truncate d (in p) to zero length. + * freeing blocks in reverse order is traditional, from Unix, + * in an attempt to keep the free list contiguous. + */ +void +dtrunc(Iobuf *p, Dentry *d, int uid) +{ + int i; + + for (i = NIBLOCK-1; i >= 0; i--) { + buffree(p->dev, d->iblocks[i], i+1, nil); + d->iblocks[i] = 0; + } + for (i = NDBLOCK-1; i >= 0; i--) { + buffree(p->dev, d->dblock[i], 0, nil); + d->dblock[i] = 0; + } + d->size = 0; + p->flags |= Bmod|Bimm; + accessdir(p, d, FWRITE, uid); +} |