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/libventi |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libventi')
35 files changed, 8124 insertions, 0 deletions
diff --git a/sys/src/libventi/cache.acid b/sys/src/libventi/cache.acid new file mode 100755 index 000000000..45b28466c --- /dev/null +++ b/sys/src/libventi/cache.acid @@ -0,0 +1,644 @@ +sizeof_1_ = 8; +aggr _1_ +{ + 'U' 0 lo; + 'U' 4 hi; +}; + +defn +_1_(addr) { + complex _1_ addr; + print(" lo ", addr.lo, "\n"); + print(" hi ", addr.hi, "\n"); +}; + +sizeofFPdbleword = 8; +aggr FPdbleword +{ + 'F' 0 x; + { + 'U' 0 lo; + 'U' 4 hi; + }; +}; + +defn +FPdbleword(addr) { + complex FPdbleword addr; + print(" x ", addr.x, "\n"); + print("_1_ {\n"); + _1_(addr+0); + print("}\n"); +}; + +UTFmax = 3; +Runesync = 128; +Runeself = 128; +Runeerror = 128; +sizeofFmt = 48; +aggr Fmt +{ + 'b' 0 runes; + 'X' 4 start; + 'X' 8 to; + 'X' 12 stop; + 'X' 16 flush; + 'X' 20 farg; + 'D' 24 nfmt; + 'X' 28 args; + 'D' 32 r; + 'D' 36 width; + 'D' 40 prec; + 'U' 44 flags; +}; + +defn +Fmt(addr) { + complex Fmt addr; + print(" runes ", addr.runes, "\n"); + print(" start ", addr.start\X, "\n"); + print(" to ", addr.to\X, "\n"); + print(" stop ", addr.stop\X, "\n"); + print(" flush ", addr.flush\X, "\n"); + print(" farg ", addr.farg\X, "\n"); + print(" nfmt ", addr.nfmt, "\n"); + print(" args ", addr.args\X, "\n"); + print(" r ", addr.r, "\n"); + print(" width ", addr.width, "\n"); + print(" prec ", addr.prec, "\n"); + print(" flags ", addr.flags, "\n"); +}; + +FmtWidth = 1; +FmtLeft = 2; +FmtPrec = 4; +FmtSharp = 8; +FmtSpace = 16; +FmtSign = 32; +FmtZero = 64; +FmtUnsigned = 128; +FmtShort = 256; +FmtLong = 512; +FmtVLong = 1024; +FmtComma = 2048; +FmtByte = 4096; +FmtFlag = 8192; +sizeofTm = 40; +aggr Tm +{ + 'D' 0 sec; + 'D' 4 min; + 'D' 8 hour; + 'D' 12 mday; + 'D' 16 mon; + 'D' 20 year; + 'D' 24 wday; + 'D' 28 yday; + 'a' 32 zone; + 'D' 36 tzoff; +}; + +defn +Tm(addr) { + complex Tm addr; + print(" sec ", addr.sec, "\n"); + print(" min ", addr.min, "\n"); + print(" hour ", addr.hour, "\n"); + print(" mday ", addr.mday, "\n"); + print(" mon ", addr.mon, "\n"); + print(" year ", addr.year, "\n"); + print(" wday ", addr.wday, "\n"); + print(" yday ", addr.yday, "\n"); + print(" zone ", addr.zone, "\n"); + print(" tzoff ", addr.tzoff, "\n"); +}; + +PNPROC = 1; +PNGROUP = 2; +sizeofLock = 4; +aggr Lock +{ + 'D' 0 val; +}; + +defn +Lock(addr) { + complex Lock addr; + print(" val ", addr.val, "\n"); +}; + +sizeofQLp = 12; +aggr QLp +{ + 'D' 0 inuse; + 'A' QLp 4 next; + 'C' 8 state; +}; + +defn +QLp(addr) { + complex QLp addr; + print(" inuse ", addr.inuse, "\n"); + print(" next ", addr.next\X, "\n"); + print(" state ", addr.state, "\n"); +}; + +sizeofQLock = 16; +aggr QLock +{ + Lock 0 lock; + 'D' 4 locked; + 'A' QLp 8 $head; + 'A' QLp 12 $tail; +}; + +defn +QLock(addr) { + complex QLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" locked ", addr.locked, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofRWLock = 20; +aggr RWLock +{ + Lock 0 lock; + 'D' 4 readers; + 'D' 8 writer; + 'A' QLp 12 $head; + 'A' QLp 16 $tail; +}; + +defn +RWLock(addr) { + complex RWLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" readers ", addr.readers, "\n"); + print(" writer ", addr.writer, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofRendez = 12; +aggr Rendez +{ + 'A' QLock 0 l; + 'A' QLp 4 $head; + 'A' QLp 8 $tail; +}; + +defn +Rendez(addr) { + complex Rendez addr; + print(" l ", addr.l\X, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofNetConnInfo = 28; +aggr NetConnInfo +{ + 'X' 0 dir; + 'X' 4 root; + 'X' 8 spec; + 'X' 12 lsys; + 'X' 16 lserv; + 'X' 20 rsys; + 'X' 24 rserv; +}; + +defn +NetConnInfo(addr) { + complex NetConnInfo addr; + print(" dir ", addr.dir\X, "\n"); + print(" root ", addr.root\X, "\n"); + print(" spec ", addr.spec\X, "\n"); + print(" lsys ", addr.lsys\X, "\n"); + print(" lserv ", addr.lserv\X, "\n"); + print(" rsys ", addr.rsys\X, "\n"); + print(" rserv ", addr.rserv\X, "\n"); +}; + +RFNAMEG = 1; +RFENVG = 2; +RFFDG = 4; +RFNOTEG = 8; +RFPROC = 16; +RFMEM = 32; +RFNOWAIT = 64; +RFCNAMEG = 1024; +RFCENVG = 2048; +RFCFDG = 4096; +RFREND = 8192; +RFNOMNT = 16384; +sizeofQid = 16; +aggr Qid +{ + 'W' 0 path; + 'U' 8 vers; + 'b' 12 type; +}; + +defn +Qid(addr) { + complex Qid addr; + print(" path ", addr.path, "\n"); + print(" vers ", addr.vers, "\n"); + print(" type ", addr.type, "\n"); +}; + +sizeofDir = 60; +aggr Dir +{ + 'u' 0 type; + 'U' 4 dev; + Qid 8 qid; + 'U' 24 mode; + 'U' 28 atime; + 'U' 32 mtime; + 'V' 36 length; + 'X' 44 name; + 'X' 48 uid; + 'X' 52 gid; + 'X' 56 muid; +}; + +defn +Dir(addr) { + complex Dir addr; + print(" type ", addr.type, "\n"); + print(" dev ", addr.dev, "\n"); + print("Qid qid {\n"); + Qid(addr.qid); + print("}\n"); + print(" mode ", addr.mode, "\n"); + print(" atime ", addr.atime, "\n"); + print(" mtime ", addr.mtime, "\n"); + print(" length ", addr.length, "\n"); + print(" name ", addr.name\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" gid ", addr.gid\X, "\n"); + print(" muid ", addr.muid\X, "\n"); +}; + +sizeofWaitmsg = 20; +aggr Waitmsg +{ + 'D' 0 pid; + 'a' 4 time; + 'X' 16 msg; +}; + +defn +Waitmsg(addr) { + complex Waitmsg addr; + print(" pid ", addr.pid, "\n"); + print(" time ", addr.time, "\n"); + print(" msg ", addr.msg\X, "\n"); +}; + +sizeofIOchunk = 8; +aggr IOchunk +{ + 'X' 0 addr; + 'U' 4 len; +}; + +defn +IOchunk(addr) { + complex IOchunk addr; + print(" addr ", addr.addr\X, "\n"); + print(" len ", addr.len, "\n"); +}; + +MaxFragSize = 9216; +VtScoreSize = 20; +VtMaxStringSize = 1024; +VtMaxFileSize = 281474976710655; +VtMaxLumpSize = 57344; +VtPointerDepth = 7; +VtDataType = 0; +VtDirType = 8; +VtRootType = 16; +VtMaxType = 17; +VtTypeDepthMask = 7; +VtEntryActive = 1; +VtEntryDir = 2; +VtEntryDepthShift = 2; +VtEntryDepthMask = 28; +VtEntryLocal = 32; +VtEntrySize = 40; +sizeofVtEntry = 40; +aggr VtEntry +{ + 'U' 0 gen; + 'u' 4 psize; + 'u' 6 dsize; + 'b' 8 type; + 'b' 9 flags; + 'W' 12 size; + 'a' 20 score; +}; + +defn +VtEntry(addr) { + complex VtEntry addr; + print(" gen ", addr.gen, "\n"); + print(" psize ", addr.psize, "\n"); + print(" dsize ", addr.dsize, "\n"); + print(" type ", addr.type, "\n"); + print(" flags ", addr.flags, "\n"); + print(" size ", addr.size, "\n"); + print(" score ", addr.score, "\n"); +}; + +sizeofVtRoot = 300; +aggr VtRoot +{ + 'a' 0 name; + 'a' 128 type; + 'a' 256 score; + 'u' 276 blocksize; + 'a' 278 prev; +}; + +defn +VtRoot(addr) { + complex VtRoot addr; + print(" name ", addr.name, "\n"); + print(" type ", addr.type, "\n"); + print(" score ", addr.score, "\n"); + print(" blocksize ", addr.blocksize, "\n"); + print(" prev ", addr.prev, "\n"); +}; + +VtRootSize = 300; +VtRootVersion = 2; +VtCryptoStrengthNone = 0; +VtCryptoStrengthAuth = 1; +VtCryptoStrengthWeak = 2; +VtCryptoStrengthStrong = 3; +VtCryptoNone = 0; +VtCryptoSSL3 = 1; +VtCryptoTLS1 = 2; +VtCryptoMax = 3; +VtCodecNone = 0; +VtCodecDeflate = 1; +VtCodecThwack = 2; +VtCodecMax = 3; +VtRerror = 1; +VtTping = 2; +VtRping = 3; +VtThello = 4; +VtRhello = 5; +VtTgoodbye = 6; +VtRgoodbye = 7; +VtTauth0 = 8; +VtRauth0 = 9; +VtTauth1 = 10; +VtRauth1 = 11; +VtTread = 12; +VtRread = 13; +VtTwrite = 14; +VtRwrite = 15; +VtTsync = 16; +VtRsync = 17; +VtTmax = 18; +sizeofVtFcall = 80; +aggr VtFcall +{ + 'b' 0 type; + 'b' 1 tag; + 'X' 4 error; + 'X' 8 version; + 'X' 12 uid; + 'b' 16 strength; + 'X' 20 crypto; + 'U' 24 ncrypto; + 'X' 28 codec; + 'U' 32 ncodec; + 'X' 36 sid; + 'b' 40 rcrypto; + 'b' 41 rcodec; + 'X' 44 auth; + 'U' 48 nauth; + 'a' 52 score; + 'b' 72 dtype; + 'u' 74 count; + 'X' 76 data; +}; + +defn +VtFcall(addr) { + complex VtFcall addr; + print(" type ", addr.type, "\n"); + print(" tag ", addr.tag, "\n"); + print(" error ", addr.error\X, "\n"); + print(" version ", addr.version\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" strength ", addr.strength, "\n"); + print(" crypto ", addr.crypto\X, "\n"); + print(" ncrypto ", addr.ncrypto, "\n"); + print(" codec ", addr.codec\X, "\n"); + print(" ncodec ", addr.ncodec, "\n"); + print(" sid ", addr.sid\X, "\n"); + print(" rcrypto ", addr.rcrypto, "\n"); + print(" rcodec ", addr.rcodec, "\n"); + print(" auth ", addr.auth\X, "\n"); + print(" nauth ", addr.nauth, "\n"); + print(" score ", addr.score, "\n"); + print(" dtype ", addr.dtype, "\n"); + print(" count ", addr.count, "\n"); + print(" data ", addr.data\X, "\n"); +}; + +VtStateAlloc = 0; +VtStateConnected = 1; +VtStateClosed = 2; +sizeofVtConn = 1148; +aggr VtConn +{ + QLock 0 lk; + QLock 16 inlk; + QLock 32 outlk; + 'D' 48 debug; + 'D' 52 infd; + 'D' 56 outfd; + 'D' 60 muxer; + 'X' 64 writeq; + 'X' 68 readq; + 'D' 72 state; + 'a' 76 wait; + 'U' 1100 ntag; + 'U' 1104 nsleep; + 'X' 1108 part; + Rendez 1112 tagrend; + Rendez 1124 rpcfork; + 'X' 1136 version; + 'X' 1140 uid; + 'X' 1144 sid; +}; + +defn +VtConn(addr) { + complex VtConn addr; + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print("QLock inlk {\n"); + QLock(addr.inlk); + print("}\n"); + print("QLock outlk {\n"); + QLock(addr.outlk); + print("}\n"); + print(" debug ", addr.debug, "\n"); + print(" infd ", addr.infd, "\n"); + print(" outfd ", addr.outfd, "\n"); + print(" muxer ", addr.muxer, "\n"); + print(" writeq ", addr.writeq\X, "\n"); + print(" readq ", addr.readq\X, "\n"); + print(" state ", addr.state, "\n"); + print(" wait ", addr.wait, "\n"); + print(" ntag ", addr.ntag, "\n"); + print(" nsleep ", addr.nsleep, "\n"); + print(" part ", addr.part\X, "\n"); + print("Rendez tagrend {\n"); + Rendez(addr.tagrend); + print("}\n"); + print("Rendez rpcfork {\n"); + Rendez(addr.rpcfork); + print("}\n"); + print(" version ", addr.version\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" sid ", addr.sid\X, "\n"); +}; + +NilBlock = -1; +sizeofVtBlock = 88; +aggr VtBlock +{ + 'X' 0 c; + QLock 4 lk; + 'X' 20 data; + 'a' 24 score; + 'b' 44 type; + 'D' 48 nlock; + 'D' 52 iostate; + 'D' 56 ref; + 'U' 60 heap; + 'A' VtBlock 64 next; + 'A' VtBlock 68 prev; + 'U' 72 used; + 'U' 76 used2; + 'U' 80 addr; + 'D' 84 decrypted; +}; + +defn +VtBlock(addr) { + complex VtBlock addr; + print(" c ", addr.c\X, "\n"); + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print(" data ", addr.data\X, "\n"); + print(" score ", addr.score, "\n"); + print(" type ", addr.type, "\n"); + print(" nlock ", addr.nlock, "\n"); + print(" iostate ", addr.iostate, "\n"); + print(" ref ", addr.ref, "\n"); + print(" heap ", addr.heap, "\n"); + print(" next ", addr.next\X, "\n"); + print(" prev ", addr.prev\X, "\n"); + print(" used ", addr.used, "\n"); + print(" used2 ", addr.used2, "\n"); + print(" addr ", addr.addr, "\n"); + print(" decrypted ", addr.decrypted, "\n"); +}; + +VtOREAD = 0; +VtOWRITE = 1; +VtORDWR = 2; +VtOCREATE = 256; +BioLocal = 1; +BioVenti = 2; +BioReading = 3; +BioWriting = 4; +BioEmpty = 5; +BioVentiError = 6; +BadHeap = -1; +sizeofVtCache = 60; +aggr VtCache +{ + QLock 0 lk; + 'A' VtConn 16 z; + 'U' 20 blocksize; + 'U' 24 now; + 'A' VtBlock 28 hash; + 'D' 32 nhash; + 'A' VtBlock 36 heap; + 'D' 40 nheap; + 'A' VtBlock 44 block; + 'D' 48 nblock; + 'X' 52 mem; + 'D' 56 mode; +}; + +defn +VtCache(addr) { + complex VtCache addr; + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print(" z ", addr.z\X, "\n"); + print(" blocksize ", addr.blocksize, "\n"); + print(" now ", addr.now, "\n"); + print(" hash ", addr.hash\X, "\n"); + print(" nhash ", addr.nhash, "\n"); + print(" heap ", addr.heap\X, "\n"); + print(" nheap ", addr.nheap, "\n"); + print(" block ", addr.block\X, "\n"); + print(" nblock ", addr.nblock, "\n"); + print(" mem ", addr.mem\X, "\n"); + print(" mode ", addr.mode, "\n"); +}; + +complex VtConn vtcachealloc:z; +complex VtCache vtcachealloc:c; +complex VtBlock vtcachealloc:b; +complex VtCache vtcachefree:c; +complex VtCache vtcachedump:c; +complex VtBlock vtcachedump:b; +complex VtCache cachecheck:c; +complex VtBlock cachecheck:b; +complex VtBlock upheap:b; +complex VtBlock upheap:bb; +complex VtCache upheap:c; +complex VtBlock downheap:b; +complex VtBlock downheap:bb; +complex VtCache downheap:c; +complex VtBlock heapdel:b; +complex VtCache heapdel:c; +complex VtBlock heapins:b; +complex VtCache vtcachebumpblock:c; +complex VtBlock vtcachebumpblock:b; +complex VtCache vtcachelocal:c; +complex VtBlock vtcachelocal:b; +complex VtCache vtcacheallocblock:c; +complex VtBlock vtcacheallocblock:b; +complex VtCache vtcacheglobal:c; +complex VtBlock vtcacheglobal:b; +complex VtBlock vtblockduplock:b; +complex VtBlock vtblockput:b; +complex VtCache vtblockput:c; +complex VtBlock vtblockwrite:b; +complex VtCache vtblockwrite:c; +complex VtCache vtcacheblocksize:c; +complex VtBlock vtblockcopy:b; +complex VtBlock vtblockcopy:bb; diff --git a/sys/src/libventi/cache.c b/sys/src/libventi/cache.c new file mode 100755 index 000000000..65e0e8c45 --- /dev/null +++ b/sys/src/libventi/cache.c @@ -0,0 +1,599 @@ +/* + * Memory-only VtBlock cache. + * + * The cached Venti blocks are in the hash chains. + * The cached local blocks are only in the blocks array. + * The free blocks are in the heap, which is supposed to + * be indexed by second-to-last use but actually + * appears to be last use. + */ + +#include <u.h> +#include <libc.h> +#include <venti.h> + +int vtcachenread; +int vtcachencopy; +int vtcachenwrite; +int vttracelevel; + +enum { + BioLocal = 1, + BioVenti, + BioReading, + BioWriting, + BioEmpty, + BioVentiError +}; +enum { + BadHeap = ~0 +}; +struct VtCache +{ + QLock lk; + VtConn *z; + u32int blocksize; + u32int now; /* ticks for usage time stamps */ + VtBlock **hash; /* hash table for finding addresses */ + int nhash; + VtBlock **heap; /* heap for finding victims */ + int nheap; + VtBlock *block; /* all allocated blocks */ + int nblock; + uchar *mem; /* memory for all blocks and data */ + int (*write)(VtConn*, uchar[VtScoreSize], uint, uchar*, int); +}; + +static void cachecheck(VtCache*); + +VtCache* +vtcachealloc(VtConn *z, int blocksize, ulong nblock) +{ + uchar *p; + VtCache *c; + int i; + VtBlock *b; + + c = vtmallocz(sizeof(VtCache)); + + c->z = z; + c->blocksize = (blocksize + 127) & ~127; + c->nblock = nblock; + c->nhash = nblock; + c->hash = vtmallocz(nblock*sizeof(VtBlock*)); + c->heap = vtmallocz(nblock*sizeof(VtBlock*)); + c->block = vtmallocz(nblock*sizeof(VtBlock)); + c->mem = vtmallocz(nblock*c->blocksize); + c->write = vtwrite; + + p = c->mem; + for(i=0; i<nblock; i++){ + b = &c->block[i]; + b->addr = NilBlock; + b->c = c; + b->data = p; + b->heap = i; + c->heap[i] = b; + p += c->blocksize; + } + c->nheap = nblock; + cachecheck(c); + return c; +} + +/* + * BUG This is here so that vbackup can override it and do some + * pipelining of writes. Arguably vtwrite or vtwritepacket or the + * cache itself should be providing this functionality. + */ +void +vtcachesetwrite(VtCache *c, int (*write)(VtConn*, uchar[VtScoreSize], uint, uchar*, int)) +{ + if(write == nil) + write = vtwrite; + c->write = write; +} + +void +vtcachefree(VtCache *c) +{ + int i; + + qlock(&c->lk); + + cachecheck(c); + for(i=0; i<c->nblock; i++) + assert(c->block[i].ref == 0); + + vtfree(c->hash); + vtfree(c->heap); + vtfree(c->block); + vtfree(c->mem); + vtfree(c); +} + +static void +vtcachedump(VtCache *c) +{ + int i; + VtBlock *b; + + for(i=0; i<c->nblock; i++){ + b = &c->block[i]; + print("cache block %d: type %d score %V iostate %d addr %d ref %d nlock %d\n", + i, b->type, b->score, b->iostate, b->addr, b->ref, b->nlock); + } +} + +static void +cachecheck(VtCache *c) +{ + u32int size, now; + int i, k, refed; + VtBlock *b; + + size = c->blocksize; + now = c->now; + + for(i = 0; i < c->nheap; i++){ + if(c->heap[i]->heap != i) + sysfatal("mis-heaped at %d: %d", i, c->heap[i]->heap); + if(i > 0 && c->heap[(i - 1) >> 1]->used - now > c->heap[i]->used - now) + sysfatal("bad heap ordering"); + k = (i << 1) + 1; + if(k < c->nheap && c->heap[i]->used - now > c->heap[k]->used - now) + sysfatal("bad heap ordering"); + k++; + if(k < c->nheap && c->heap[i]->used - now > c->heap[k]->used - now) + sysfatal("bad heap ordering"); + } + + refed = 0; + for(i = 0; i < c->nblock; i++){ + b = &c->block[i]; + if(b->data != &c->mem[i * size]) + sysfatal("mis-blocked at %d", i); + if(b->ref && b->heap == BadHeap) + refed++; + else if(b->addr != NilBlock) + refed++; + } + assert(c->nheap + refed == c->nblock); + refed = 0; + for(i = 0; i < c->nblock; i++){ + b = &c->block[i]; + if(b->ref){ + refed++; + } + } +} + +static int +upheap(int i, VtBlock *b) +{ + VtBlock *bb; + u32int now; + int p; + VtCache *c; + + c = b->c; + now = c->now; + for(; i != 0; i = p){ + p = (i - 1) >> 1; + bb = c->heap[p]; + if(b->used - now >= bb->used - now) + break; + c->heap[i] = bb; + bb->heap = i; + } + c->heap[i] = b; + b->heap = i; + + return i; +} + +static int +downheap(int i, VtBlock *b) +{ + VtBlock *bb; + u32int now; + int k; + VtCache *c; + + c = b->c; + now = c->now; + for(; ; i = k){ + k = (i << 1) + 1; + if(k >= c->nheap) + break; + if(k + 1 < c->nheap && c->heap[k]->used - now > c->heap[k + 1]->used - now) + k++; + bb = c->heap[k]; + if(b->used - now <= bb->used - now) + break; + c->heap[i] = bb; + bb->heap = i; + } + c->heap[i] = b; + b->heap = i; + return i; +} + +/* + * Delete a block from the heap. + * Called with c->lk held. + */ +static void +heapdel(VtBlock *b) +{ + int i, si; + VtCache *c; + + c = b->c; + + si = b->heap; + if(si == BadHeap) + return; + b->heap = BadHeap; + c->nheap--; + if(si == c->nheap) + return; + b = c->heap[c->nheap]; + i = upheap(si, b); + if(i == si) + downheap(i, b); +} + +/* + * Insert a block into the heap. + * Called with c->lk held. + */ +static void +heapins(VtBlock *b) +{ + assert(b->heap == BadHeap); + upheap(b->c->nheap++, b); +} + +/* + * locate the vtBlock with the oldest second to last use. + * remove it from the heap, and fix up the heap. + */ +/* called with c->lk held */ +static VtBlock* +vtcachebumpblock(VtCache *c) +{ + VtBlock *b; + + /* + * locate the vtBlock with the oldest second to last use. + * remove it from the heap, and fix up the heap. + */ + if(c->nheap == 0){ + vtcachedump(c); + fprint(2, "vtcachebumpblock: no free blocks in vtCache"); + abort(); + } + b = c->heap[0]; + heapdel(b); + + assert(b->heap == BadHeap); + assert(b->ref == 0); + + /* + * unchain the vtBlock from hash chain if any + */ + if(b->prev){ + *(b->prev) = b->next; + if(b->next) + b->next->prev = b->prev; + b->prev = nil; + } + + +if(0)fprint(2, "droping %x:%V\n", b->addr, b->score); + /* set vtBlock to a reasonable state */ + b->ref = 1; + b->iostate = BioEmpty; + return b; +} + +/* + * fetch a local block from the memory cache. + * if it's not there, load it, bumping some other Block. + * if we're out of free blocks, we're screwed. + */ +VtBlock* +vtcachelocal(VtCache *c, u32int addr, int type) +{ + VtBlock *b; + + if(addr == 0) + sysfatal("vtcachelocal: asked for nonexistent block 0"); + if(addr > c->nblock) + sysfatal("vtcachelocal: asked for block #%ud; only %d blocks", + addr, c->nblock); + + b = &c->block[addr-1]; + if(b->addr == NilBlock || b->iostate != BioLocal) + sysfatal("vtcachelocal: block is not local"); + + if(b->type != type) + sysfatal("vtcachelocal: block has wrong type %d != %d", b->type, type); + + qlock(&c->lk); + b->ref++; + qunlock(&c->lk); + + qlock(&b->lk); + b->nlock = 1; + b->pc = getcallerpc(&c); + return b; +} + +VtBlock* +vtcacheallocblock(VtCache *c, int type) +{ + VtBlock *b; + + qlock(&c->lk); + b = vtcachebumpblock(c); + b->iostate = BioLocal; + b->type = type; + b->addr = (b - c->block)+1; + vtzeroextend(type, b->data, 0, c->blocksize); + vtlocaltoglobal(b->addr, b->score); + qunlock(&c->lk); + + qlock(&b->lk); + b->nlock = 1; + b->pc = getcallerpc(&c); + return b; +} + +/* + * fetch a global (Venti) block from the memory cache. + * if it's not there, load it, bumping some other block. + */ +VtBlock* +vtcacheglobal(VtCache *c, uchar score[VtScoreSize], int type) +{ + VtBlock *b; + ulong h; + int n; + u32int addr; + + if(vttracelevel) + fprint(2, "vtcacheglobal %V %d from %p\n", score, type, getcallerpc(&c)); + addr = vtglobaltolocal(score); + if(addr != NilBlock){ + if(vttracelevel) + fprint(2, "vtcacheglobal %V %d => local\n", score, type); + b = vtcachelocal(c, addr, type); + if(b) + b->pc = getcallerpc(&c); + return b; + } + + h = (u32int)(score[0]|(score[1]<<8)|(score[2]<<16)|(score[3]<<24)) % c->nhash; + + /* + * look for the block in the cache + */ + qlock(&c->lk); + for(b = c->hash[h]; b != nil; b = b->next){ + if(b->addr != NilBlock || memcmp(b->score, score, VtScoreSize) != 0 || b->type != type) + continue; + heapdel(b); + b->ref++; + qunlock(&c->lk); + if(vttracelevel) + fprint(2, "vtcacheglobal %V %d => found in cache %p; locking\n", score, type, b); + qlock(&b->lk); + b->nlock = 1; + if(b->iostate == BioVentiError){ + if(chattyventi) + fprint(2, "cached read error for %V\n", score); + if(vttracelevel) + fprint(2, "vtcacheglobal %V %d => cache read error\n", score, type); + vtblockput(b); + werrstr("venti i/o error"); + return nil; + } + if(vttracelevel) + fprint(2, "vtcacheglobal %V %d => found in cache; returning\n", score, type); + b->pc = getcallerpc(&c); + return b; + } + + /* + * not found + */ + b = vtcachebumpblock(c); + b->addr = NilBlock; + b->type = type; + memmove(b->score, score, VtScoreSize); + /* chain onto correct hash */ + b->next = c->hash[h]; + c->hash[h] = b; + if(b->next != nil) + b->next->prev = &b->next; + b->prev = &c->hash[h]; + + /* + * Lock b before unlocking c, so that others wait while we read. + * + * You might think there is a race between this qlock(b) before qunlock(c) + * and the qlock(c) while holding a qlock(b) in vtblockwrite. However, + * the block here can never be the block in a vtblockwrite, so we're safe. + * We're certainly living on the edge. + */ + if(vttracelevel) + fprint(2, "vtcacheglobal %V %d => bumped; locking %p\n", score, type, b); + qlock(&b->lk); + b->nlock = 1; + qunlock(&c->lk); + + vtcachenread++; + n = vtread(c->z, score, type, b->data, c->blocksize); + if(n < 0){ + if(chattyventi) + fprint(2, "read %V: %r\n", score); + if(vttracelevel) + fprint(2, "vtcacheglobal %V %d => bumped; read error\n", score, type); + b->iostate = BioVentiError; + vtblockput(b); + return nil; + } + vtzeroextend(type, b->data, n, c->blocksize); + b->iostate = BioVenti; + b->nlock = 1; + if(vttracelevel) + fprint(2, "vtcacheglobal %V %d => loaded into cache; returning\n", score, type); + b->pc = getcallerpc(&b); + return b; +} + +/* + * The thread that has locked b may refer to it by + * multiple names. Nlock counts the number of + * references the locking thread holds. It will call + * vtblockput once per reference. + */ +void +vtblockduplock(VtBlock *b) +{ + assert(b->nlock > 0); + b->nlock++; +} + +/* + * we're done with the block. + * unlock it. can't use it after calling this. + */ +void +vtblockput(VtBlock* b) +{ + VtCache *c; + + if(b == nil) + return; + +if(0)fprint(2, "vtblockput: %d: %x %d %d\n", getpid(), b->addr, c->nheap, b->iostate); + if(vttracelevel) + fprint(2, "vtblockput %p from %p\n", b, getcallerpc(&b)); + + if(--b->nlock > 0) + return; + + /* + * b->nlock should probably stay at zero while + * the vtBlock is unlocked, but diskThread and vtSleep + * conspire to assume that they can just qlock(&b->lk); vtblockput(b), + * so we have to keep b->nlock set to 1 even + * when the vtBlock is unlocked. + */ + assert(b->nlock == 0); + b->nlock = 1; + + qunlock(&b->lk); + c = b->c; + qlock(&c->lk); + + if(--b->ref > 0){ + qunlock(&c->lk); + return; + } + + assert(b->ref == 0); + switch(b->iostate){ + case BioVenti: +/*if(b->addr != NilBlock) print("blockput %d\n", b->addr); */ + b->used = c->now++; + /* fall through */ + case BioVentiError: + heapins(b); + break; + case BioLocal: + break; + } + qunlock(&c->lk); +} + +int +vtblockwrite(VtBlock *b) +{ + uchar score[VtScoreSize]; + VtCache *c; + uint h; + int n; + + if(b->iostate != BioLocal){ + werrstr("vtblockwrite: not a local block"); + return -1; + } + + c = b->c; + n = vtzerotruncate(b->type, b->data, c->blocksize); + vtcachenwrite++; + if(c->write(c->z, score, b->type, b->data, n) < 0) + return -1; + + memmove(b->score, score, VtScoreSize); + + qlock(&c->lk); + b->addr = NilBlock; /* now on venti */ + b->iostate = BioVenti; + h = (u32int)(score[0]|(score[1]<<8)|(score[2]<<16)|(score[3]<<24)) % c->nhash; + b->next = c->hash[h]; + c->hash[h] = b; + if(b->next != nil) + b->next->prev = &b->next; + b->prev = &c->hash[h]; + qunlock(&c->lk); + return 0; +} + +uint +vtcacheblocksize(VtCache *c) +{ + return c->blocksize; +} + +VtBlock* +vtblockcopy(VtBlock *b) +{ + VtBlock *bb; + + vtcachencopy++; + bb = vtcacheallocblock(b->c, b->type); + if(bb == nil){ + vtblockput(b); + return nil; + } + memmove(bb->data, b->data, b->c->blocksize); + vtblockput(b); + bb->pc = getcallerpc(&b); + return bb; +} + +void +vtlocaltoglobal(u32int addr, uchar score[VtScoreSize]) +{ + memset(score, 0, 16); + score[16] = addr>>24; + score[17] = addr>>16; + score[18] = addr>>8; + score[19] = addr; +} + + +u32int +vtglobaltolocal(uchar score[VtScoreSize]) +{ + static uchar zero[16]; + if(memcmp(score, zero, 16) != 0) + return NilBlock; + return (score[16]<<24)|(score[17]<<16)|(score[18]<<8)|score[19]; +} + diff --git a/sys/src/libventi/client.c b/sys/src/libventi/client.c new file mode 100755 index 000000000..40ee85175 --- /dev/null +++ b/sys/src/libventi/client.c @@ -0,0 +1,180 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +int ventidoublechecksha1 = 1; + +static int +vtfcallrpc(VtConn *z, VtFcall *ou, VtFcall *in) +{ + Packet *p; + + p = vtfcallpack(ou); + if(p == nil) + return -1; + if((p = _vtrpc(z, p, ou)) == nil) + return -1; + if(vtfcallunpack(in, p) < 0){ + packetfree(p); + return -1; + } + if(chattyventi) + fprint(2, "%s <- %F\n", argv0, in); + if(in->msgtype == VtRerror){ + werrstr(in->error); + vtfcallclear(in); + packetfree(p); + return -1; + } + if(in->msgtype != ou->msgtype+1){ + werrstr("type mismatch: sent %c%d got %c%d", + "TR"[ou->msgtype&1], ou->msgtype>>1, + "TR"[in->msgtype&1], in->msgtype>>1); + vtfcallclear(in); + packetfree(p); + return -1; + } + packetfree(p); + return 0; +} + +int +vthello(VtConn *z) +{ + VtFcall tx, rx; + + memset(&tx, 0, sizeof tx); + tx.msgtype = VtThello; + tx.version = z->version; + tx.uid = z->uid; + if(tx.uid == nil) + tx.uid = "anonymous"; + if(vtfcallrpc(z, &tx, &rx) < 0) + return -1; + z->sid = rx.sid; + rx.sid = 0; + vtfcallclear(&rx); + return 0; +} + +Packet* +vtreadpacket(VtConn *z, uchar score[VtScoreSize], uint type, int n) +{ + VtFcall tx, rx; + + if(memcmp(score, vtzeroscore, VtScoreSize) == 0) + return packetalloc(); + + memset(&tx, 0, sizeof tx); + tx.msgtype = VtTread; + tx.blocktype = type; + tx.count = n; + memmove(tx.score, score, VtScoreSize); + if(vtfcallrpc(z, &tx, &rx) < 0) + return nil; + if(packetsize(rx.data) > n){ + werrstr("read returned too much data"); + packetfree(rx.data); + return nil; + } + if(ventidoublechecksha1){ + packetsha1(rx.data, tx.score); + if(memcmp(score, tx.score, VtScoreSize) != 0){ + werrstr("read asked for %V got %V", score, tx.score); + packetfree(rx.data); + return nil; + } + } + return rx.data; +} + +int +vtread(VtConn *z, uchar score[VtScoreSize], uint type, uchar *buf, int n) +{ + int nn; + Packet *p; + + if((p = vtreadpacket(z, score, type, n)) == nil) + return -1; + nn = packetsize(p); + if(packetconsume(p, buf, nn) < 0) + abort(); + packetfree(p); + return nn; +} + +int +vtwritepacket(VtConn *z, uchar score[VtScoreSize], uint type, Packet *p) +{ + VtFcall tx, rx; + + if(packetsize(p) == 0){ + memmove(score, vtzeroscore, VtScoreSize); + return 0; + } + tx.msgtype = VtTwrite; + tx.blocktype = type; + tx.data = p; + if(ventidoublechecksha1) + packetsha1(p, score); + if(vtfcallrpc(z, &tx, &rx) < 0) + return -1; + if(ventidoublechecksha1){ + if(memcmp(score, rx.score, VtScoreSize) != 0){ + werrstr("sha1 hash mismatch: want %V got %V", score, rx.score); + return -1; + } + }else + memmove(score, rx.score, VtScoreSize); + return 0; +} + +int +vtwrite(VtConn *z, uchar score[VtScoreSize], uint type, uchar *buf, int n) +{ + Packet *p; + int nn; + + p = packetforeign(buf, n, 0, nil); + nn = vtwritepacket(z, score, type, p); + packetfree(p); + return nn; +} + +int +vtsync(VtConn *z) +{ + VtFcall tx, rx; + + tx.msgtype = VtTsync; + return vtfcallrpc(z, &tx, &rx); +} + +int +vtping(VtConn *z) +{ + VtFcall tx, rx; + + tx.msgtype = VtTping; + return vtfcallrpc(z, &tx, &rx); +} + +int +vtconnect(VtConn *z) +{ + if(vtversion(z) < 0) + return -1; + if(vthello(z) < 0) + return -1; + return 0; +} + +int +vtgoodbye(VtConn *z) +{ + VtFcall tx, rx; + + tx.msgtype = VtTgoodbye; + vtfcallrpc(z, &tx, &rx); /* always fails: no VtRgoodbye */ + return 0; +} diff --git a/sys/src/libventi/conn.c b/sys/src/libventi/conn.c new file mode 100755 index 000000000..e488c6db6 --- /dev/null +++ b/sys/src/libventi/conn.c @@ -0,0 +1,51 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> +#include "queue.h" + +int chattyventi; + +VtConn* +vtconn(int infd, int outfd) +{ + VtConn *z; + NetConnInfo *nci; + + z = vtmallocz(sizeof(VtConn)); + z->tagrend.l = &z->lk; + z->rpcfork.l = &z->lk; + z->infd = infd; + z->outfd = outfd; + z->part = packetalloc(); + nci = getnetconninfo(nil, infd); + if(nci == nil) + snprint(z->addr, sizeof z->addr, "/dev/fd/%d", infd); + else{ + strecpy(z->addr, z->addr+sizeof z->addr, nci->raddr); + freenetconninfo(nci); + } + return z; +} + +void +vtfreeconn(VtConn *z) +{ + vthangup(z); + qlock(&z->lk); + /* + * Wait for send and recv procs to notice + * the hangup and clear out the queues. + */ + while(z->readq || z->writeq){ + if(z->readq) + _vtqhangup(z->readq); + if(z->writeq) + _vtqhangup(z->writeq); + rsleep(&z->rpcfork); + } + packetfree(z->part); + vtfree(z->version); + vtfree(z->sid); + qunlock(&z->lk); + vtfree(z); +} diff --git a/sys/src/libventi/cvt.h b/sys/src/libventi/cvt.h new file mode 100755 index 000000000..ef4c2f51d --- /dev/null +++ b/sys/src/libventi/cvt.h @@ -0,0 +1,15 @@ +/* + * integer conversion routines + */ +#define U8GET(p) ((p)[0]) +#define U16GET(p) (((p)[0]<<8)|(p)[1]) +#define U32GET(p) ((u32int)(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])) +#define U48GET(p) (((vlong)U16GET(p)<<32)|(vlong)U32GET((p)+2)) +#define U64GET(p) (((vlong)U32GET(p)<<32)|(vlong)U32GET((p)+4)) + +#define U8PUT(p,v) (p)[0]=(v) +#define U16PUT(p,v) (p)[0]=(v)>>8;(p)[1]=(v) +#define U32PUT(p,v) (p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v) +#define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32) +#define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32) + diff --git a/sys/src/libventi/debug.c b/sys/src/libventi/debug.c new file mode 100755 index 000000000..e0452e48d --- /dev/null +++ b/sys/src/libventi/debug.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +void +vtdebug(VtConn *z, char *fmt, ...) +{ + va_list arg; + + if(z->debug == 0) + return; + + va_start(arg, fmt); + vfprint(2, fmt, arg); + va_end(arg); +} + diff --git a/sys/src/libventi/debugpacket.c b/sys/src/libventi/debugpacket.c new file mode 100755 index 000000000..4c13bc87e --- /dev/null +++ b/sys/src/libventi/debugpacket.c @@ -0,0 +1,265 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> +#include <libsec.h> + +#define MAGIC 0x54798314 +#define NOTFREE(p) assert((p)->magic == MAGIC) + +struct Packet +{ + char *data; + int len; + void (*free)(void*); + void *arg; + int magic; +}; + +Packet* +packetalloc(void) +{ + Packet *p; + + p = vtmallocz(sizeof *p); + p->free = vtfree; + p->arg = nil; + p->magic = MAGIC; + return p; +} + +void +packetappend(Packet *p, uchar *buf, int n) +{ + NOTFREE(p); + if(n < 0) + abort(); + if(p->free != vtfree) + sysfatal("packetappend"); + p->data = vtrealloc(p->data, p->len+n); + p->arg = p->data; + memmove(p->data+p->len, buf, n); + p->len += n; +} + +uint +packetasize(Packet *p) +{ + NOTFREE(p); + return p->len; +} + +int +packetcmp(Packet *p, Packet *q) +{ + int i, len; + + NOTFREE(p); + NOTFREE(q); + len = p->len; + if(len > q->len) + len = q->len; + if(len && (i=memcmp(p->data, q->data, len)) != 0) + return i; + if(p->len > len) + return 1; + if(q->len > len) + return -1; + return 0; +} + +void +packetconcat(Packet *p, Packet *q) +{ + NOTFREE(p); + NOTFREE(q); + packetappend(p, q->data, q->len); + if(q->free == vtfree) + memset(q->data, 0xFE, q->len); + q->free(q->arg); + q->data = nil; + q->len = 0; +} + +int +packetconsume(Packet *p, uchar *buf, int n) +{ + NOTFREE(p); + if(n < 0) + abort(); + if(p->len < n) + abort(); + memmove(buf, p->data, n); + p->len -= n; + memmove(p->data, p->data+n, p->len); + return 0; +} + +int +packetcopy(Packet *p, uchar *buf, int offset, int n) +{ + NOTFREE(p); + if(offset < 0 || n < 0) + abort(); + if(offset > p->len) + abort(); + if(offset+n > p->len) + n = p->len - offset; + memmove(buf, p->data+offset, n); + return 0; +} + +Packet* +packetdup(Packet *p, int offset, int n) +{ + Packet *q; + + NOTFREE(p); + if(offset < 0 || n < 0) + abort(); + if(offset > p->len) + abort(); + if(offset+n > p->len) + n = p->len - offset; + q = packetalloc(); + packetappend(q, p->data+offset, n); + return q; +} + +Packet* +packetforeign(uchar *buf, int n, void (*free)(void*), void *a) +{ + Packet *p; + + if(n < 0) + abort(); + p = packetalloc(); + p->data = (char*)buf; + p->len = n; + p->free = free; + p->arg = a; + return p; +} + +int +packetfragments(Packet *p, IOchunk *io, int nio, int offset) +{ + NOTFREE(p); + if(offset < 0) + abort(); + if(nio == 0) + return 0; + memset(io, 0, sizeof(io[0])*nio); + if(offset >= p->len) + return 0; + io[0].addr = p->data + offset; + io[0].len = p->len - offset; + return p->len; +} + +void +packetfree(Packet *p) +{ + NOTFREE(p); + if(p->free == free) + memset(p->data, 0xFE, p->len); + p->free(p->arg); + p->data = nil; + p->len = 0; + memset(p, 0xFB, sizeof *p); + free(p); +} + +uchar* +packetheader(Packet *p, int n) +{ + NOTFREE(p); + if(n < 0) + abort(); + if(n > p->len) + abort(); + return p->data; +} + +uchar* +packetpeek(Packet *p, uchar *buf, int offset, int n) +{ + NOTFREE(p); + if(offset < 0 || n < 0) + abort(); + if(offset+n > p->len) + abort(); + return p->data+offset; +} + +void +packetprefix(Packet *p, uchar *buf, int n) +{ + NOTFREE(p); + if(n < 0) + abort(); + if(p->free != free) + sysfatal("packetappend"); + p->data = vtrealloc(p->data, p->len+n); + p->arg = p->data; + memmove(p->data+n, p->data, p->len); + memmove(p->data, buf, n); + p->len += n; +} + +void +packetsha1(Packet *p, uchar d[20]) +{ + NOTFREE(p); + sha1((uchar*)p->data, p->len, d, nil); +} + +uint +packetsize(Packet *p) +{ + NOTFREE(p); + return p->len; +} + +Packet* +packetsplit(Packet *p, int n) +{ + Packet *q; + + NOTFREE(p); + q = packetalloc(); + q->data = vtmalloc(n); + q->arg = q->data; + q->free = vtfree; + packetconsume(p, q->data, n); + return q; +} + +void +packetstats(void) +{ +} + +uchar* +packettrailer(Packet *p, int n) +{ + NOTFREE(p); + if(n < 0) + abort(); + if(n > p->len) + abort(); + return p->data + p->len - n; +} + +int +packettrim(Packet *p, int offset, int n) +{ + NOTFREE(p); + if(offset < 0 || n < 0) + abort(); + if(offset+n > p->len) + abort(); + memmove(p->data+offset, p->data+offset+n, p->len-offset-n); + p->len -= n; + return 0; +} + diff --git a/sys/src/libventi/dial.c b/sys/src/libventi/dial.c new file mode 100755 index 000000000..060b93f61 --- /dev/null +++ b/sys/src/libventi/dial.c @@ -0,0 +1,25 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +VtConn* +vtdial(char *addr) +{ + char *na; + int fd; + VtConn *z; + + if(addr == nil) + addr = getenv("venti"); + if(addr == nil) + addr = "$venti"; + + na = netmkaddr(addr, "tcp", "venti"); + if((fd = dial(na, nil, nil, nil)) < 0) + return nil; + + z = vtconn(fd, fd); + if(z) + strecpy(z->addr, z->addr+sizeof z->addr, na); + return z; +} diff --git a/sys/src/libventi/dtype.c b/sys/src/libventi/dtype.c new file mode 100755 index 000000000..7886518e2 --- /dev/null +++ b/sys/src/libventi/dtype.c @@ -0,0 +1,78 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +enum { + OVtErrType, /* illegal */ + + OVtRootType, + OVtDirType, + OVtPointerType0, + OVtPointerType1, + OVtPointerType2, + OVtPointerType3, + OVtPointerType4, + OVtPointerType5, + OVtPointerType6, + OVtPointerType7, /* not used */ + OVtPointerType8, /* not used */ + OVtPointerType9, /* not used */ + OVtDataType, + + OVtMaxType +}; + + +uint todisk[] = { + OVtDataType, + OVtPointerType0, + OVtPointerType1, + OVtPointerType2, + OVtPointerType3, + OVtPointerType4, + OVtPointerType5, + OVtPointerType6, + OVtDirType, + OVtPointerType0, + OVtPointerType1, + OVtPointerType2, + OVtPointerType3, + OVtPointerType4, + OVtPointerType5, + OVtPointerType6, + OVtRootType, +}; + +uint fromdisk[] = { + VtCorruptType, + VtRootType, + VtDirType, + VtDirType+1, + VtDirType+2, + VtDirType+3, + VtDirType+4, + VtDirType+5, + VtDirType+6, + VtDirType+7, + VtCorruptType, + VtCorruptType, + VtCorruptType, + VtDataType, +}; + +uint +vttodisktype(uint n) +{ + if(n >= nelem(todisk)) + return VtCorruptType; + return todisk[n]; +} + +uint +vtfromdisktype(uint n) +{ + if(n >= nelem(fromdisk)) + return VtCorruptType; + return fromdisk[n]; +} + diff --git a/sys/src/libventi/entry.c b/sys/src/libventi/entry.c new file mode 100755 index 000000000..aeb8dada3 --- /dev/null +++ b/sys/src/libventi/entry.c @@ -0,0 +1,95 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> +#include "cvt.h" + +static int +checksize(int n) +{ + if(n < 256 || n > VtMaxLumpSize) { + werrstr("bad block size %#ux", n); + return -1; + } + return 0; +} + +void +vtentrypack(VtEntry *e, uchar *p, int index) +{ + ulong t32; + int flags; + uchar *op; + int depth; + + p += index * VtEntrySize; + op = p; + + U32PUT(p, e->gen); + p += 4; + U16PUT(p, e->psize); + p += 2; + U16PUT(p, e->dsize); + p += 2; + depth = e->type&VtTypeDepthMask; + flags = (e->flags&~(_VtEntryDir|_VtEntryDepthMask)); + flags |= depth << _VtEntryDepthShift; + if(e->type - depth == VtDirType) + flags |= _VtEntryDir; + U8PUT(p, flags); + p++; + memset(p, 0, 5); + p += 5; + U48PUT(p, e->size, t32); + p += 6; + memmove(p, e->score, VtScoreSize); + p += VtScoreSize; + + assert(p-op == VtEntrySize); +} + +int +vtentryunpack(VtEntry *e, uchar *p, int index) +{ + uchar *op; + + p += index * VtEntrySize; + op = p; + + e->gen = U32GET(p); + p += 4; + e->psize = U16GET(p); + p += 2; + e->dsize = U16GET(p); + p += 2; + e->flags = U8GET(p); + e->type = (e->flags&_VtEntryDir) ? VtDirType : VtDataType; + e->type += (e->flags & _VtEntryDepthMask) >> _VtEntryDepthShift; + e->flags &= ~(_VtEntryDir|_VtEntryDepthMask); + p++; + p += 5; + e->size = U48GET(p); + p += 6; + memmove(e->score, p, VtScoreSize); + p += VtScoreSize; + + assert(p-op == VtEntrySize); + + if(!(e->flags & VtEntryActive)) + return 0; + + /* + * Some old vac files use psize==0 and dsize==0 when the + * file itself has size 0 or is zeros. Just to make programs not + * have to figure out what block sizes of 0 means, rewrite them. + */ + if(e->psize == 0 && e->dsize == 0 + && memcmp(e->score, vtzeroscore, VtScoreSize) == 0){ + e->psize = 4096; + e->dsize = 4096; + } + if(checksize(e->psize) < 0 || checksize(e->dsize) < 0) + return -1; + + return 0; +} + diff --git a/sys/src/libventi/fcall.c b/sys/src/libventi/fcall.c new file mode 100755 index 000000000..65ee2d178 --- /dev/null +++ b/sys/src/libventi/fcall.c @@ -0,0 +1,231 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +Packet* +vtfcallpack(VtFcall *f) +{ + uchar buf[4]; + Packet *p; + + p = packetalloc(); + + buf[0] = f->msgtype; + buf[1] = f->tag; + packetappend(p, buf, 2); + + switch(f->msgtype){ + default: + werrstr("vtfcallpack: unknown packet type %d", f->msgtype); + goto Err; + + case VtRerror: + if(vtputstring(p, f->error) < 0) + goto Err; + break; + + case VtTping: + break; + + case VtRping: + break; + + case VtThello: + if(vtputstring(p, f->version) < 0 + || vtputstring(p, f->uid) < 0) + goto Err; + buf[0] = f->strength; + buf[1] = f->ncrypto; + packetappend(p, buf, 2); + packetappend(p, f->crypto, f->ncrypto); + buf[0] = f->ncodec; + packetappend(p, buf, 1); + packetappend(p, f->codec, f->ncodec); + break; + + case VtRhello: + if(vtputstring(p, f->sid) < 0) + goto Err; + buf[0] = f->rcrypto; + buf[1] = f->rcodec; + packetappend(p, buf, 2); + break; + + case VtTgoodbye: + break; + + case VtTread: + packetappend(p, f->score, VtScoreSize); + buf[0] = vttodisktype(f->blocktype); + if(~buf[0] == 0) + goto Err; + buf[1] = 0; + buf[2] = f->count >> 8; + buf[3] = f->count; + packetappend(p, buf, 4); + break; + + case VtRread: + packetconcat(p, f->data); + break; + + case VtTwrite: + buf[0] = vttodisktype(f->blocktype); + if(~buf[0] == 0) + goto Err; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + packetappend(p, buf, 4); + packetconcat(p, f->data); + break; + + case VtRwrite: + packetappend(p, f->score, VtScoreSize); + break; + + case VtTsync: + break; + + case VtRsync: + break; + } + + return p; + +Err: + packetfree(p); + return nil; +} + +int +vtfcallunpack(VtFcall *f, Packet *p) +{ + uchar buf[4]; + + memset(f, 0, sizeof *f); + + if(packetconsume(p, buf, 2) < 0) + return -1; + + f->msgtype = buf[0]; + f->tag = buf[1]; + + switch(f->msgtype){ + default: + werrstr("vtfcallunpack: unknown bad packet type %d", f->msgtype); + vtfcallclear(f); + return -1; + + case VtRerror: + if(vtgetstring(p, &f->error) < 0) + goto Err; + break; + + case VtTping: + break; + + case VtRping: + break; + + case VtThello: + if(vtgetstring(p, &f->version) < 0 + || vtgetstring(p, &f->uid) < 0 + || packetconsume(p, buf, 2) < 0) + goto Err; + f->strength = buf[0]; + f->ncrypto = buf[1]; + if(f->ncrypto){ + f->crypto = vtmalloc(f->ncrypto); + if(packetconsume(p, buf, f->ncrypto) < 0) + goto Err; + } + if(packetconsume(p, buf, 1) < 0) + goto Err; + f->ncodec = buf[0]; + if(f->ncodec){ + f->codec = vtmalloc(f->ncodec); + if(packetconsume(p, buf, f->ncodec) < 0) + goto Err; + } + break; + + case VtRhello: + if(vtgetstring(p, &f->sid) < 0 + || packetconsume(p, buf, 2) < 0) + goto Err; + f->rcrypto = buf[0]; + f->rcodec = buf[1]; + break; + + case VtTgoodbye: + break; + + case VtTread: + if(packetconsume(p, f->score, VtScoreSize) < 0 + || packetconsume(p, buf, 4) < 0) + goto Err; + f->blocktype = vtfromdisktype(buf[0]); + if(~f->blocktype == 0) + goto Err; + f->count = (buf[2] << 8) | buf[3]; + break; + + case VtRread: + f->data = packetalloc(); + packetconcat(f->data, p); + break; + + case VtTwrite: + if(packetconsume(p, buf, 4) < 0) + goto Err; + f->blocktype = vtfromdisktype(buf[0]); + if(~f->blocktype == 0) + goto Err; + f->data = packetalloc(); + packetconcat(f->data, p); + break; + + case VtRwrite: + if(packetconsume(p, f->score, VtScoreSize) < 0) + goto Err; + break; + + case VtTsync: + break; + + case VtRsync: + break; + } + + if(packetsize(p) != 0) + goto Err; + + return 0; + +Err: + werrstr("bad packet"); + vtfcallclear(f); + return -1; +} + +void +vtfcallclear(VtFcall *f) +{ + vtfree(f->error); + f->error = nil; + vtfree(f->uid); + f->uid = nil; + vtfree(f->sid); + f->sid = nil; + vtfree(f->version); + f->version = nil; + vtfree(f->crypto); + f->crypto = nil; + vtfree(f->codec); + f->codec = nil; + vtfree(f->auth); + f->auth = nil; + packetfree(f->data); + f->data = nil; +} diff --git a/sys/src/libventi/fcallfmt.c b/sys/src/libventi/fcallfmt.c new file mode 100755 index 000000000..9b493f9aa --- /dev/null +++ b/sys/src/libventi/fcallfmt.c @@ -0,0 +1,55 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +int +vtfcallfmt(Fmt *f) +{ + VtFcall *t; + + t = va_arg(f->args, VtFcall*); + if(t == nil){ + fmtprint(f, "<nil fcall>"); + return 0; + } + switch(t->msgtype){ + default: + return fmtprint(f, "%c%d tag %ud", "TR"[t->msgtype&1], t->msgtype>>1, t->tag); + case VtRerror: + return fmtprint(f, "Rerror tag %ud error %s", t->tag, t->error); + case VtTping: + return fmtprint(f, "Tping tag %ud", t->tag); + case VtRping: + return fmtprint(f, "Rping tag %ud", t->tag); + case VtThello: + return fmtprint(f, "Thello tag %ud vers %s uid %s strength %d crypto %d:%.*H codec %d:%.*H", t->tag, + t->version, t->uid, t->strength, t->ncrypto, t->ncrypto, t->crypto, + t->ncodec, t->ncodec, t->codec); + case VtRhello: + return fmtprint(f, "Rhello tag %ud sid %s rcrypto %d rcodec %d", t->tag, t->sid, t->rcrypto, t->rcodec); + case VtTgoodbye: + return fmtprint(f, "Tgoodbye tag %ud", t->tag); + case VtRgoodbye: + return fmtprint(f, "Rgoodbye tag %ud", t->tag); + case VtTauth0: + return fmtprint(f, "Tauth0 tag %ud auth %.*H", t->tag, t->nauth, t->auth); + case VtRauth0: + return fmtprint(f, "Rauth0 tag %ud auth %.*H", t->tag, t->nauth, t->auth); + case VtTauth1: + return fmtprint(f, "Tauth1 tag %ud auth %.*H", t->tag, t->nauth, t->auth); + case VtRauth1: + return fmtprint(f, "Rauth1 tag %ud auth %.*H", t->tag, t->nauth, t->auth); + case VtTread: + return fmtprint(f, "Tread tag %ud score %V blocktype %d count %d", t->tag, t->score, t->blocktype, t->count); + case VtRread: + return fmtprint(f, "Rread tag %ud count %d", t->tag, packetsize(t->data)); + case VtTwrite: + return fmtprint(f, "Twrite tag %ud blocktype %d count %d", t->tag, t->blocktype, packetsize(t->data)); + case VtRwrite: + return fmtprint(f, "Rwrite tag %ud score %V", t->tag, t->score); + case VtTsync: + return fmtprint(f, "Tsync tag %ud", t->tag); + case VtRsync: + return fmtprint(f, "Rsync tag %ud", t->tag); + } +} diff --git a/sys/src/libventi/file.c b/sys/src/libventi/file.c new file mode 100755 index 000000000..b6887dec7 --- /dev/null +++ b/sys/src/libventi/file.c @@ -0,0 +1,1282 @@ +/* + * Manage tree of VtFiles stored in the block cache. + * + * The single point of truth for the info about the VtFiles themselves + * is the block data. Because of this, there is no explicit locking of + * VtFile structures, and indeed there may be more than one VtFile + * structure for a given Venti file. They synchronize through the + * block cache. + * + * This is a bit simpler than fossil because there are no epochs + * or tags or anything else. Just mutable local blocks and immutable + * Venti blocks. + */ + +#include <u.h> +#include <libc.h> +#include <venti.h> + +#define MaxBlock (1UL<<31) + +static char ENotDir[] = "walk in non-directory"; +static char ETooBig[] = "file too big"; +/* static char EBadAddr[] = "bad address"; */ +static char ELabelMismatch[] = "label mismatch"; + +static int sizetodepth(uvlong s, int psize, int dsize); +static VtBlock *fileload(VtFile *r, VtEntry *e); +static int shrinkdepth(VtFile*, VtBlock*, VtEntry*, int); +static int shrinksize(VtFile*, VtEntry*, uvlong); +static int growdepth(VtFile*, VtBlock*, VtEntry*, int); + +#define ISLOCKED(r) ((r)->b != nil) +#define DEPTH(t) ((t)&VtTypeDepthMask) + +static VtFile * +vtfilealloc(VtCache *c, VtBlock *b, VtFile *p, u32int offset, int mode) +{ + int epb; + u32int size; + VtEntry e; + VtFile *r; + + assert(p==nil || ISLOCKED(p)); + + if(p == nil){ + assert(offset == 0); + epb = 1; + }else + epb = p->dsize / VtEntrySize; + + if(b->type != VtDirType){ + werrstr("bad block type %#uo", b->type); + return nil; + } + + /* + * a non-active entry is the only thing that + * can legitimately happen here. all the others + * get prints. + */ + if(vtentryunpack(&e, b->data, offset % epb) < 0){ + fprint(2, "vtentryunpack failed: %r (%.*H)\n", VtEntrySize, b->data+VtEntrySize*(offset%epb)); + return nil; + } + if(!(e.flags & VtEntryActive)){ + werrstr("entry not active"); + return nil; + } + + if(DEPTH(e.type) < sizetodepth(e.size, e.psize, e.dsize)){ + fprint(2, "depth %ud size %llud psize %ud dsize %ud\n", + DEPTH(e.type), e.size, e.psize, e.dsize); + werrstr("bad depth"); + return nil; + } + + size = vtcacheblocksize(c); + if(e.dsize > size || e.psize > size){ + werrstr("block sizes %ud, %ud bigger than cache block size %ud", + e.psize, e.dsize, size); + return nil; + } + + r = vtmallocz(sizeof(VtFile)); + r->c = c; + r->mode = mode; + r->dsize = e.dsize; + r->psize = e.psize; + r->gen = e.gen; + r->dir = (e.type & VtTypeBaseMask) == VtDirType; + r->ref = 1; + r->parent = p; + if(p){ + qlock(&p->lk); + assert(mode == VtOREAD || p->mode == VtORDWR); + p->ref++; + qunlock(&p->lk); + }else{ + assert(b->addr != NilBlock); + r->local = 1; + } + memmove(r->score, b->score, VtScoreSize); + r->offset = offset; + r->epb = epb; + + return r; +} + +VtFile * +vtfileroot(VtCache *c, u32int addr, int mode) +{ + VtFile *r; + VtBlock *b; + + b = vtcachelocal(c, addr, VtDirType); + if(b == nil) + return nil; + r = vtfilealloc(c, b, nil, 0, mode); + vtblockput(b); + return r; +} + +VtFile* +vtfileopenroot(VtCache *c, VtEntry *e) +{ + VtBlock *b; + VtFile *f; + + b = vtcacheallocblock(c, VtDirType); + if(b == nil) + return nil; + + vtentrypack(e, b->data, 0); + f = vtfilealloc(c, b, nil, 0, VtORDWR); + vtblockput(b); + return f; +} + +VtFile * +vtfilecreateroot(VtCache *c, int psize, int dsize, int type) +{ + VtEntry e; + + memset(&e, 0, sizeof e); + e.flags = VtEntryActive; + e.psize = psize; + e.dsize = dsize; + e.type = type; + memmove(e.score, vtzeroscore, VtScoreSize); + + return vtfileopenroot(c, &e); +} + +VtFile * +vtfileopen(VtFile *r, u32int offset, int mode) +{ + ulong bn; + VtBlock *b; + + assert(ISLOCKED(r)); + if(!r->dir){ + werrstr(ENotDir); + return nil; + } + + bn = offset/(r->dsize/VtEntrySize); + + b = vtfileblock(r, bn, mode); + if(b == nil) + return nil; + r = vtfilealloc(r->c, b, r, offset, mode); + vtblockput(b); + return r; +} + +VtFile* +vtfilecreate(VtFile *r, int psize, int dsize, int type) +{ + return _vtfilecreate(r, -1, psize, dsize, type); +} + +VtFile* +_vtfilecreate(VtFile *r, int o, int psize, int dsize, int type) +{ + int i; + VtBlock *b; + u32int bn, size; + VtEntry e; + int epb; + VtFile *rr; + u32int offset; + + assert(ISLOCKED(r)); + assert(psize <= VtMaxLumpSize); + assert(dsize <= VtMaxLumpSize); + assert(type == VtDirType || type == VtDataType); + + if(!r->dir){ + werrstr(ENotDir); + return nil; + } + + epb = r->dsize/VtEntrySize; + + size = vtfilegetdirsize(r); + /* + * look at a random block to see if we can find an empty entry + */ + if(o == -1){ + offset = lnrand(size+1); + offset -= offset % epb; + }else + offset = o; + + /* try the given block and then try the last block */ + for(;;){ + bn = offset/epb; + b = vtfileblock(r, bn, VtORDWR); + if(b == nil) + return nil; + for(i=offset%r->epb; i<epb; i++){ + if(vtentryunpack(&e, b->data, i) < 0) + continue; + if((e.flags&VtEntryActive) == 0 && e.gen != ~0) + goto Found; + } + vtblockput(b); + if(offset == size){ + fprint(2, "vtfilecreate: cannot happen\n"); + werrstr("vtfilecreate: cannot happen"); + return nil; + } + offset = size; + } + +Found: + /* found an entry - gen already set */ + e.psize = psize; + e.dsize = dsize; + e.flags = VtEntryActive; + e.type = type; + e.size = 0; + memmove(e.score, vtzeroscore, VtScoreSize); + vtentrypack(&e, b->data, i); + + offset = bn*epb + i; + if(offset+1 > size){ + if(vtfilesetdirsize(r, offset+1) < 0){ + vtblockput(b); + return nil; + } + } + + rr = vtfilealloc(r->c, b, r, offset, VtORDWR); + vtblockput(b); + return rr; +} + +static int +vtfilekill(VtFile *r, int doremove) +{ + VtEntry e; + VtBlock *b; + + assert(ISLOCKED(r)); + b = fileload(r, &e); + if(b == nil) + return -1; + + if(doremove==0 && e.size == 0){ + /* already truncated */ + vtblockput(b); + return 0; + } + + if(doremove){ + if(e.gen != ~0) + e.gen++; + e.dsize = 0; + e.psize = 0; + e.flags = 0; + }else + e.flags &= ~VtEntryLocal; + e.type = 0; + e.size = 0; + memmove(e.score, vtzeroscore, VtScoreSize); + vtentrypack(&e, b->data, r->offset % r->epb); + vtblockput(b); + + if(doremove){ + vtfileunlock(r); + vtfileclose(r); + } + + return 0; +} + +int +vtfileremove(VtFile *r) +{ + return vtfilekill(r, 1); +} + +int +vtfiletruncate(VtFile *r) +{ + return vtfilekill(r, 0); +} + +uvlong +vtfilegetsize(VtFile *r) +{ + VtEntry e; + VtBlock *b; + + assert(ISLOCKED(r)); + b = fileload(r, &e); + if(b == nil) + return ~(uvlong)0; + vtblockput(b); + + return e.size; +} + +static int +shrinksize(VtFile *r, VtEntry *e, uvlong size) +{ + int i, depth, type, isdir, ppb; + uvlong ptrsz; + uchar score[VtScoreSize]; + VtBlock *b; + + b = vtcacheglobal(r->c, e->score, e->type); + if(b == nil) + return -1; + + ptrsz = e->dsize; + ppb = e->psize/VtScoreSize; + type = e->type; + depth = DEPTH(type); + for(i=0; i+1<depth; i++) + ptrsz *= ppb; + + isdir = r->dir; + while(depth > 0){ + if(b->addr == NilBlock){ + /* not worth copying the block just so we can zero some of it */ + vtblockput(b); + return -1; + } + + /* + * invariant: each pointer in the tree rooted at b accounts for ptrsz bytes + */ + + /* zero the pointers to unnecessary blocks */ + i = (size+ptrsz-1)/ptrsz; + for(; i<ppb; i++) + memmove(b->data+i*VtScoreSize, vtzeroscore, VtScoreSize); + + /* recurse (go around again) on the partially necessary block */ + i = size/ptrsz; + size = size%ptrsz; + if(size == 0){ + vtblockput(b); + return 0; + } + ptrsz /= ppb; + type--; + memmove(score, b->data+i*VtScoreSize, VtScoreSize); + vtblockput(b); + b = vtcacheglobal(r->c, score, type); + if(b == nil) + return -1; + } + + if(b->addr == NilBlock){ + vtblockput(b); + return -1; + } + + /* + * No one ever truncates BtDir blocks. + */ + if(depth==0 && !isdir && e->dsize > size) + memset(b->data+size, 0, e->dsize-size); + vtblockput(b); + return 0; +} + +int +vtfilesetsize(VtFile *r, u64int size) +{ + int depth, edepth; + VtEntry e; + VtBlock *b; + + assert(ISLOCKED(r)); + if(size == 0) + return vtfiletruncate(r); + + if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize){ + werrstr(ETooBig); + return -1; + } + + b = fileload(r, &e); + if(b == nil) + return -1; + + /* quick out */ + if(e.size == size){ + vtblockput(b); + return 0; + } + + depth = sizetodepth(size, e.psize, e.dsize); + edepth = DEPTH(e.type); + if(depth < edepth){ + if(shrinkdepth(r, b, &e, depth) < 0){ + vtblockput(b); + return -1; + } + }else if(depth > edepth){ + if(growdepth(r, b, &e, depth) < 0){ + vtblockput(b); + return -1; + } + } + + if(size < e.size) + shrinksize(r, &e, size); + + e.size = size; + vtentrypack(&e, b->data, r->offset % r->epb); + vtblockput(b); + + return 0; +} + +int +vtfilesetdirsize(VtFile *r, u32int ds) +{ + uvlong size; + int epb; + + assert(ISLOCKED(r)); + epb = r->dsize/VtEntrySize; + + size = (uvlong)r->dsize*(ds/epb); + size += VtEntrySize*(ds%epb); + return vtfilesetsize(r, size); +} + +u32int +vtfilegetdirsize(VtFile *r) +{ + ulong ds; + uvlong size; + int epb; + + assert(ISLOCKED(r)); + epb = r->dsize/VtEntrySize; + + size = vtfilegetsize(r); + ds = epb*(size/r->dsize); + ds += (size%r->dsize)/VtEntrySize; + return ds; +} + +int +vtfilegetentry(VtFile *r, VtEntry *e) +{ + VtBlock *b; + + assert(ISLOCKED(r)); + b = fileload(r, e); + if(b == nil) + return -1; + vtblockput(b); + + return 0; +} + +int +vtfilesetentry(VtFile *r, VtEntry *e) +{ + VtBlock *b; + VtEntry ee; + + assert(ISLOCKED(r)); + b = fileload(r, &ee); + if(b == nil) + return -1; + vtentrypack(e, b->data, r->offset % r->epb); + vtblockput(b); + return 0; +} + +static VtBlock * +blockwalk(VtBlock *p, int index, VtCache *c, int mode, VtEntry *e) +{ + VtBlock *b; + int type; + uchar *score; + VtEntry oe; + + switch(p->type){ + case VtDataType: + assert(0); + case VtDirType: + type = e->type; + score = e->score; + break; + default: + type = p->type - 1; + score = p->data+index*VtScoreSize; + break; + } +/*print("walk from %V/%d ty %d to %V ty %d\n", p->score, index, p->type, score, type); */ + + if(mode == VtOWRITE && vtglobaltolocal(score) == NilBlock){ + b = vtcacheallocblock(c, type); + if(b) + goto HaveCopy; + }else + b = vtcacheglobal(c, score, type); + + if(b == nil || mode == VtOREAD) + return b; + + if(vtglobaltolocal(b->score) != NilBlock) + return b; + + oe = *e; + + /* + * Copy on write. + */ + e->flags |= VtEntryLocal; + + b = vtblockcopy(b/*, e->tag, fs->ehi, fs->elo*/); + if(b == nil) + return nil; + +HaveCopy: + if(p->type == VtDirType){ + memmove(e->score, b->score, VtScoreSize); + vtentrypack(e, p->data, index); + }else{ + memmove(p->data+index*VtScoreSize, b->score, VtScoreSize); + } + return b; +} + +/* + * Change the depth of the VtFile r. + * The entry e for r is contained in block p. + */ +static int +growdepth(VtFile *r, VtBlock *p, VtEntry *e, int depth) +{ + VtBlock *b, *bb; + VtEntry oe; + + assert(ISLOCKED(r)); + assert(depth <= VtPointerDepth); + + b = vtcacheglobal(r->c, e->score, e->type); + if(b == nil) + return -1; + + oe = *e; + + /* + * Keep adding layers until we get to the right depth + * or an error occurs. + */ + while(DEPTH(e->type) < depth){ + bb = vtcacheallocblock(r->c, e->type+1); + if(bb == nil) + break; + memmove(bb->data, b->score, VtScoreSize); + memmove(e->score, bb->score, VtScoreSize); + e->type++; + e->flags |= VtEntryLocal; + vtblockput(b); + b = bb; + } + + vtentrypack(e, p->data, r->offset % r->epb); + vtblockput(b); + + if(DEPTH(e->type) == depth) + return 0; + return -1; +} + +static int +shrinkdepth(VtFile *r, VtBlock *p, VtEntry *e, int depth) +{ + VtBlock *b, *nb, *ob, *rb; + VtEntry oe; + + assert(ISLOCKED(r)); + assert(depth <= VtPointerDepth); + + rb = vtcacheglobal(r->c, e->score, e->type); + if(rb == nil) + return -1; + + /* + * Walk down to the new root block. + * We may stop early, but something is better than nothing. + */ + oe = *e; + + ob = nil; + b = rb; + for(; DEPTH(e->type) > depth; e->type--){ + nb = vtcacheglobal(r->c, b->data, e->type-1); + if(nb == nil) + break; + if(ob!=nil && ob!=rb) + vtblockput(ob); + ob = b; + b = nb; + } + + if(b == rb){ + vtblockput(rb); + return 0; + } + + /* + * Right now, e points at the root block rb, b is the new root block, + * and ob points at b. To update: + * + * (i) change e to point at b + * (ii) zero the pointer ob -> b + * (iii) free the root block + * + * p (the block containing e) must be written before + * anything else. + */ + + /* (i) */ + memmove(e->score, b->score, VtScoreSize); + vtentrypack(e, p->data, r->offset % r->epb); + + /* (ii) */ + memmove(ob->data, vtzeroscore, VtScoreSize); + + /* (iii) */ + vtblockput(rb); + if(ob!=nil && ob!=rb) + vtblockput(ob); + vtblockput(b); + + if(DEPTH(e->type) == depth) + return 0; + return -1; +} + +static int +mkindices(VtEntry *e, u32int bn, int *index) +{ + int i, np; + + memset(index, 0, (VtPointerDepth+1)*sizeof(int)); + + np = e->psize/VtScoreSize; + for(i=0; bn > 0; i++){ + if(i >= VtPointerDepth){ + werrstr("bad address 0x%lux", (ulong)bn); + return -1; + } + index[i] = bn % np; + bn /= np; + } + return i; +} + +VtBlock * +vtfileblock(VtFile *r, u32int bn, int mode) +{ + VtBlock *b, *bb; + int index[VtPointerDepth+1]; + VtEntry e; + int i; + int m; + + assert(ISLOCKED(r)); + assert(bn != NilBlock); + + b = fileload(r, &e); + if(b == nil) + return nil; + + i = mkindices(&e, bn, index); + if(i < 0) + goto Err; + if(i > DEPTH(e.type)){ + if(mode == VtOREAD){ + werrstr("bad address 0x%lux", (ulong)bn); + goto Err; + } + index[i] = 0; + if(growdepth(r, b, &e, i) < 0) + goto Err; + } + +assert(b->type == VtDirType); + + index[DEPTH(e.type)] = r->offset % r->epb; + + /* mode for intermediate block */ + m = mode; + if(m == VtOWRITE) + m = VtORDWR; + + for(i=DEPTH(e.type); i>=0; i--){ + bb = blockwalk(b, index[i], r->c, i==0 ? mode : m, &e); + if(bb == nil) + goto Err; + vtblockput(b); + b = bb; + } + b->pc = getcallerpc(&r); + return b; +Err: + vtblockput(b); + return nil; +} + +int +vtfileblockscore(VtFile *r, u32int bn, uchar score[VtScoreSize]) +{ + VtBlock *b, *bb; + int index[VtPointerDepth+1]; + VtEntry e; + int i; + + assert(ISLOCKED(r)); + assert(bn != NilBlock); + + b = fileload(r, &e); + if(b == nil) + return -1; + + if(DEPTH(e.type) == 0){ + memmove(score, e.score, VtScoreSize); + vtblockput(b); + return 0; + } + + i = mkindices(&e, bn, index); + if(i < 0){ + vtblockput(b); + return -1; + } + if(i > DEPTH(e.type)){ + memmove(score, vtzeroscore, VtScoreSize); + vtblockput(b); + return 0; + } + + index[DEPTH(e.type)] = r->offset % r->epb; + + for(i=DEPTH(e.type); i>=1; i--){ + bb = blockwalk(b, index[i], r->c, VtOREAD, &e); + if(bb == nil) + goto Err; + vtblockput(b); + b = bb; + if(memcmp(b->score, vtzeroscore, VtScoreSize) == 0) + break; + } + + memmove(score, b->data+index[0]*VtScoreSize, VtScoreSize); + vtblockput(b); + return 0; + +Err: + vtblockput(b); + return -1; +} + +void +vtfileincref(VtFile *r) +{ + qlock(&r->lk); + r->ref++; + qunlock(&r->lk); +} + +void +vtfileclose(VtFile *r) +{ + if(r == nil) + return; + qlock(&r->lk); + r->ref--; + if(r->ref){ + qunlock(&r->lk); + return; + } + assert(r->ref == 0); + qunlock(&r->lk); + if(r->parent) + vtfileclose(r->parent); + memset(r, ~0, sizeof(*r)); + vtfree(r); +} + +/* + * Retrieve the block containing the entry for r. + * If a snapshot has happened, we might need + * to get a new copy of the block. We avoid this + * in the common case by caching the score for + * the block and the last epoch in which it was valid. + * + * We use r->mode to tell the difference between active + * file system VtFiles (VtORDWR) and VtFiles for the + * snapshot file system (VtOREAD). + */ +static VtBlock* +fileloadblock(VtFile *r, int mode) +{ + char e[ERRMAX]; + u32int addr; + VtBlock *b; + + switch(r->mode){ + default: + assert(0); + case VtORDWR: + assert(r->mode == VtORDWR); + if(r->local == 1){ + b = vtcacheglobal(r->c, r->score, VtDirType); + if(b == nil) + return nil; + b->pc = getcallerpc(&r); + return b; + } + assert(r->parent != nil); + if(vtfilelock(r->parent, VtORDWR) < 0) + return nil; + b = vtfileblock(r->parent, r->offset/r->epb, VtORDWR); + vtfileunlock(r->parent); + if(b == nil) + return nil; + memmove(r->score, b->score, VtScoreSize); + r->local = 1; + return b; + + case VtOREAD: + if(mode == VtORDWR){ + werrstr("read/write lock of read-only file"); + return nil; + } + addr = vtglobaltolocal(r->score); + if(addr == NilBlock) + return vtcacheglobal(r->c, r->score, VtDirType); + + b = vtcachelocal(r->c, addr, VtDirType); + if(b) + return b; + + /* + * If it failed because the epochs don't match, the block has been + * archived and reclaimed. Rewalk from the parent and get the + * new pointer. This can't happen in the VtORDWR case + * above because blocks in the current epoch don't get + * reclaimed. The fact that we're VtOREAD means we're + * a snapshot. (Or else the file system is read-only, but then + * the archiver isn't going around deleting blocks.) + */ + rerrstr(e, sizeof e); + if(strcmp(e, ELabelMismatch) == 0){ + if(vtfilelock(r->parent, VtOREAD) < 0) + return nil; + b = vtfileblock(r->parent, r->offset/r->epb, VtOREAD); + vtfileunlock(r->parent); + if(b){ + fprint(2, "vtfilealloc: lost %V found %V\n", + r->score, b->score); + memmove(r->score, b->score, VtScoreSize); + return b; + } + } + return nil; + } +} + +int +vtfilelock(VtFile *r, int mode) +{ + VtBlock *b; + + if(mode == -1) + mode = r->mode; + + b = fileloadblock(r, mode); + if(b == nil) + return -1; + /* + * The fact that we are holding b serves as the + * lock entitling us to write to r->b. + */ + assert(r->b == nil); + r->b = b; + b->pc = getcallerpc(&r); + return 0; +} + +/* + * Lock two (usually sibling) VtFiles. This needs special care + * because the Entries for both vtFiles might be in the same block. + * We also try to lock blocks in left-to-right order within the tree. + */ +int +vtfilelock2(VtFile *r, VtFile *rr, int mode) +{ + VtBlock *b, *bb; + + if(rr == nil) + return vtfilelock(r, mode); + + if(mode == -1) + mode = r->mode; + + if(r->parent==rr->parent && r->offset/r->epb == rr->offset/rr->epb){ + b = fileloadblock(r, mode); + if(b == nil) + return -1; + vtblockduplock(b); + bb = b; + }else if(r->parent==rr->parent || r->offset > rr->offset){ + bb = fileloadblock(rr, mode); + b = fileloadblock(r, mode); + }else{ + b = fileloadblock(r, mode); + bb = fileloadblock(rr, mode); + } + if(b == nil || bb == nil){ + if(b) + vtblockput(b); + if(bb) + vtblockput(bb); + return -1; + } + + /* + * The fact that we are holding b and bb serves + * as the lock entitling us to write to r->b and rr->b. + */ + r->b = b; + rr->b = bb; + b->pc = getcallerpc(&r); + bb->pc = getcallerpc(&r); + return 0; +} + +void +vtfileunlock(VtFile *r) +{ + VtBlock *b; + + if(r->b == nil){ + fprint(2, "vtfileunlock: already unlocked\n"); + abort(); + } + b = r->b; + r->b = nil; + vtblockput(b); +} + +static VtBlock* +fileload(VtFile *r, VtEntry *e) +{ + VtBlock *b; + + assert(ISLOCKED(r)); + b = r->b; + if(vtentryunpack(e, b->data, r->offset % r->epb) < 0) + return nil; + vtblockduplock(b); + return b; +} + +static int +sizetodepth(uvlong s, int psize, int dsize) +{ + int np; + int d; + + /* determine pointer depth */ + np = psize/VtScoreSize; + s = (s + dsize - 1)/dsize; + for(d = 0; s > 1; d++) + s = (s + np - 1)/np; + return d; +} + +long +vtfileread(VtFile *f, void *data, long count, vlong offset) +{ + int frag; + VtBlock *b; + VtEntry e; + + assert(ISLOCKED(f)); + + vtfilegetentry(f, &e); + if(count == 0) + return 0; + if(count < 0 || offset < 0){ + werrstr("vtfileread: bad offset or count"); + return -1; + } + if(offset >= e.size) + return 0; + + if(offset+count > e.size) + count = e.size - offset; + + frag = offset % e.dsize; + if(frag+count > e.dsize) + count = e.dsize - frag; + + b = vtfileblock(f, offset/e.dsize, VtOREAD); + if(b == nil) + return -1; + + memmove(data, b->data+frag, count); + vtblockput(b); + return count; +} + +static long +filewrite1(VtFile *f, void *data, long count, vlong offset) +{ + int frag, m; + VtBlock *b; + VtEntry e; + + vtfilegetentry(f, &e); + if(count < 0 || offset < 0){ + werrstr("vtfilewrite: bad offset or count"); + return -1; + } + + frag = offset % e.dsize; + if(frag+count > e.dsize) + count = e.dsize - frag; + + m = VtORDWR; + if(frag == 0 && count == e.dsize) + m = VtOWRITE; + + b = vtfileblock(f, offset/e.dsize, m); + if(b == nil) + return -1; + + memmove(b->data+frag, data, count); + if(m == VtOWRITE && frag+count < e.dsize) + memset(b->data+frag+count, 0, e.dsize-frag-count); + + if(offset+count > e.size){ + vtfilegetentry(f, &e); + e.size = offset+count; + vtfilesetentry(f, &e); + } + + vtblockput(b); + return count; +} + +long +vtfilewrite(VtFile *f, void *data, long count, vlong offset) +{ + long tot, m; + + assert(ISLOCKED(f)); + + tot = 0; + m = 0; + while(tot < count){ + m = filewrite1(f, (char*)data+tot, count-tot, offset+tot); + if(m <= 0) + break; + tot += m; + } + if(tot==0) + return m; + return tot; +} + +static int +flushblock(VtCache *c, VtBlock *bb, uchar score[VtScoreSize], int ppb, int epb, + int type) +{ + u32int addr; + VtBlock *b; + VtEntry e; + int i; + + addr = vtglobaltolocal(score); + if(addr == NilBlock) + return 0; + + if(bb){ + b = bb; + if(memcmp(b->score, score, VtScoreSize) != 0) + abort(); + }else + if((b = vtcachelocal(c, addr, type)) == nil) + return -1; + + switch(type){ + case VtDataType: + break; + + case VtDirType: + for(i=0; i<epb; i++){ + if(vtentryunpack(&e, b->data, i) < 0) + goto Err; + if(!(e.flags&VtEntryActive)) + continue; + if(flushblock(c, nil, e.score, e.psize/VtScoreSize, e.dsize/VtEntrySize, + e.type) < 0) + goto Err; + vtentrypack(&e, b->data, i); + } + break; + + default: /* VtPointerTypeX */ + for(i=0; i<ppb; i++){ + if(flushblock(c, nil, b->data+VtScoreSize*i, ppb, epb, type-1) < 0) + goto Err; + } + break; + } + + if(vtblockwrite(b) < 0) + goto Err; + memmove(score, b->score, VtScoreSize); + if(b != bb) + vtblockput(b); + return 0; + +Err: + if(b != bb) + vtblockput(b); + return -1; +} + +int +vtfileflush(VtFile *f) +{ + int ret; + VtBlock *b; + VtEntry e; + + assert(ISLOCKED(f)); + b = fileload(f, &e); + if(!(e.flags&VtEntryLocal)){ + vtblockput(b); + return 0; + } + + ret = flushblock(f->c, nil, e.score, e.psize/VtScoreSize, e.dsize/VtEntrySize, + e.type); + if(ret < 0){ + vtblockput(b); + return -1; + } + + vtentrypack(&e, b->data, f->offset % f->epb); + vtblockput(b); + return 0; +} + +int +vtfileflushbefore(VtFile *r, u64int offset) +{ + VtBlock *b, *bb; + VtEntry e; + int i, base, depth, ppb, epb, doflush; + int index[VtPointerDepth+1], j, ret; + VtBlock *bi[VtPointerDepth+2]; + uchar *score; + + assert(ISLOCKED(r)); + if(offset == 0) + return 0; + + b = fileload(r, &e); + if(b == nil) + return -1; + + /* + * compute path through tree for the last written byte and the next one. + */ + ret = -1; + memset(bi, 0, sizeof bi); + depth = DEPTH(e.type); + bi[depth+1] = b; + i = mkindices(&e, (offset-1)/e.dsize, index); + if(i < 0) + goto Err; + if(i > depth) + goto Err; + ppb = e.psize / VtScoreSize; + epb = e.dsize / VtEntrySize; + + /* + * load the blocks along the last written byte + */ + index[depth] = r->offset % r->epb; + for(i=depth; i>=0; i--){ + bb = blockwalk(b, index[i], r->c, VtORDWR, &e); + if(bb == nil) + goto Err; + bi[i] = bb; + b = bb; + } + ret = 0; + + /* + * walk up the path from leaf to root, flushing anything that + * has been finished. + */ + base = e.type&~VtTypeDepthMask; + for(i=0; i<=depth; i++){ + doflush = 0; + if(i == 0){ + /* leaf: data or dir block */ + if(offset%e.dsize == 0) + doflush = 1; + }else{ + /* + * interior node: pointer blocks. + * specifically, b = bi[i] is a block whose index[i-1]'th entry + * points at bi[i-1]. + */ + b = bi[i]; + + /* + * the index entries up to but not including index[i-1] point at + * finished blocks, so flush them for sure. + */ + for(j=0; j<index[i-1]; j++) + if(flushblock(r->c, nil, b->data+j*VtScoreSize, ppb, epb, base+i-1) < 0) + goto Err; + + /* + * if index[i-1] is the last entry in the block and is global + * (i.e. the kid is flushed), then we can flush this block. + */ + if(j==ppb-1 && vtglobaltolocal(b->data+j*VtScoreSize)==NilBlock) + doflush = 1; + } + if(doflush){ + if(i == depth) + score = e.score; + else + score = bi[i+1]->data+index[i]*VtScoreSize; + if(flushblock(r->c, bi[i], score, ppb, epb, base+i) < 0) + goto Err; + } + } + +Err: + /* top: entry. do this always so that the score is up-to-date */ + vtentrypack(&e, bi[depth+1]->data, index[depth]); + for(i=0; i<nelem(bi); i++) + if(bi[i]) + vtblockput(bi[i]); + return ret; +} diff --git a/sys/src/libventi/hangup.c b/sys/src/libventi/hangup.c new file mode 100755 index 000000000..365baf1da --- /dev/null +++ b/sys/src/libventi/hangup.c @@ -0,0 +1,31 @@ +#include <u.h> +#ifdef PLAN9PORT +#include <sys/socket.h> +#endif +#include <libc.h> +#include <venti.h> +#include "queue.h" + +void +vthangup(VtConn *z) +{ + qlock(&z->lk); + z->state = VtStateClosed; +#ifdef PLAN9PORT + /* try to make the read in vtrecvproc fail */ + shutdown(SHUT_WR, z->infd); + shutdown(SHUT_WR, z->outfd); +#endif + if(z->infd >= 0) + close(z->infd); + if(z->outfd >= 0 && z->outfd != z->infd) + close(z->outfd); + z->infd = -1; + z->outfd = -1; + if(z->writeq) + _vtqhangup(z->writeq); + if(z->readq) + _vtqhangup(z->readq); + qunlock(&z->lk); +} + diff --git a/sys/src/libventi/log.c b/sys/src/libventi/log.c new file mode 100755 index 000000000..80a1d4787 --- /dev/null +++ b/sys/src/libventi/log.c @@ -0,0 +1,256 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +char *VtServerLog = "libventi/server"; + +int ventilogging; +#define log not_the_log_library_call + +static char Eremoved[] = "[removed]"; + +enum +{ /* defaults */ + LogChunkSize = 8192, + LogSize = 65536 +}; + +static struct { + QLock lk; + VtLog *hash[1024]; +} vl; + +static uint +hash(char *s) +{ + uint h; + uchar *p; + + h = 0; + for(p=(uchar*)s; *p; p++) + h = h*37 + *p; + return h; +} + +char** +vtlognames(int *pn) +{ + int i, nname, size; + VtLog *l; + char **s, *a, *e; + + qlock(&vl.lk); + size = 0; + nname = 0; + for(i=0; i<nelem(vl.hash); i++) + for(l=vl.hash[i]; l; l=l->next){ + nname++; + size += strlen(l->name)+1; + } + + s = vtmalloc(nname*sizeof(char*)+size); + a = (char*)(s+nname); + e = (char*)s+nname*sizeof(char*)+size; + + nname = 0; + for(i=0; i<nelem(vl.hash); i++) + for(l=vl.hash[i]; l; l=l->next){ + strcpy(a, l->name); + s[nname++] = a; + a += strlen(a)+1; + } + *pn = nname; + assert(a == e); + qunlock(&vl.lk); + + return s; +} + +VtLog* +vtlogopen(char *name, uint size) +{ + uint h; + int i, nc; + char *p; + VtLog *l, *last; + + if(!ventilogging) + return nil; + + h = hash(name)%nelem(vl.hash); + qlock(&vl.lk); + last = nil; + for(l=vl.hash[h]; l; last=l, l=l->next) + if(strcmp(l->name, name) == 0){ + if(last){ /* move to front */ + last->next = l->next; + l->next = vl.hash[h]; + vl.hash[h] = l; + } + l->ref++; + qunlock(&vl.lk); + return l; + } + + if(size == 0){ + qunlock(&vl.lk); + return nil; + } + + /* allocate */ + nc = (size+LogChunkSize-1)/LogChunkSize; + l = vtmalloc(sizeof *l + nc*(sizeof(*l->chunk)+LogChunkSize) + strlen(name)+1); + memset(l, 0, sizeof *l); + l->chunk = (VtLogChunk*)(l+1); + l->nchunk = nc; + l->w = l->chunk; + p = (char*)(l->chunk+nc); + for(i=0; i<nc; i++){ + l->chunk[i].p = p; + l->chunk[i].wp = p; + p += LogChunkSize; + l->chunk[i].ep = p; + } + strcpy(p, name); + l->name = p; + + /* insert */ + l->next = vl.hash[h]; + vl.hash[h] = l; + l->ref++; + + l->ref++; + qunlock(&vl.lk); + return l; +} + +void +vtlogclose(VtLog *l) +{ + if(l == nil) + return; + + qlock(&vl.lk); + if(--l->ref == 0){ + /* must not be in hash table */ + assert(l->name == Eremoved); + free(l); + }else + assert(l->ref > 0); + qunlock(&vl.lk); +} + +void +vtlogremove(char *name) +{ + uint h; + VtLog *last, *l; + + h = hash(name)%nelem(vl.hash); + qlock(&vl.lk); + last = nil; + for(l=vl.hash[h]; l; last=l, l=l->next) + if(strcmp(l->name, name) == 0){ + if(last) + last->next = l->next; + else + vl.hash[h] = l->next; + l->name = Eremoved; + l->next = nil; + qunlock(&vl.lk); + vtlogclose(l); + return; + } + qunlock(&vl.lk); +} + +static int +timefmt(Fmt *fmt) +{ + static uvlong t0; + uvlong t; + + if(t0 == 0) + t0 = nsec(); + t = nsec()-t0; + return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000); +} + +void +vtlogvprint(VtLog *l, char *fmt, va_list arg) +{ + int n; + char *p; + VtLogChunk *c; + static int first = 1; + + if(l == nil) + return; + + if(first){ + fmtinstall('T', timefmt); + first = 0; + } + + + qlock(&l->lk); + c = l->w; + n = c->ep - c->wp; + if(n < 512){ + c++; + if(c == l->chunk+l->nchunk) + c = l->chunk; + c->wp = c->p; + l->w = c; + } + p = vseprint(c->wp, c->ep, fmt, arg); + if(p) + c->wp = p; + qunlock(&l->lk); +} + +void +vtlogprint(VtLog *l, char *fmt, ...) +{ + va_list arg; + + if(l == nil) + return; + + va_start(arg, fmt); + vtlogvprint(l, fmt, arg); + va_end(arg); +} + +void +vtlog(char *name, char *fmt, ...) +{ + VtLog *l; + va_list arg; + + l = vtlogopen(name, LogSize); + if(l == nil) + return; + va_start(arg, fmt); + vtlogvprint(l, fmt, arg); + va_end(arg); + vtlogclose(l); +} + +void +vtlogdump(int fd, VtLog *l) +{ + int i; + VtLogChunk *c; + + if(l == nil) + return; + + c = l->w; + for(i=0; i<l->nchunk; i++){ + if(++c == l->chunk+l->nchunk) + c = l->chunk; + write(fd, c->p, c->wp-c->p); + } +} + diff --git a/sys/src/libventi/mem.c b/sys/src/libventi/mem.c new file mode 100755 index 000000000..dea99a9d1 --- /dev/null +++ b/sys/src/libventi/mem.c @@ -0,0 +1,86 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +enum { + IdealAlignment = 32, + ChunkSize = 128*1024 +}; + + +void +vtfree(void *p) +{ + if(p == 0) + return; + free(p); +} + +void * +vtmalloc(int size) +{ + void *p; + + p = malloc(size); + if(p == 0) + sysfatal("vtmalloc: out of memory"); + setmalloctag(p, getcallerpc(&size)); + return p; +} + +void * +vtmallocz(int size) +{ + void *p = vtmalloc(size); + memset(p, 0, size); + setmalloctag(p, getcallerpc(&size)); + return p; +} + +void * +vtrealloc(void *p, int size) +{ + if(p == nil) + return vtmalloc(size); + p = realloc(p, size); + if(p == 0) + sysfatal("vtMemRealloc: out of memory"); + setrealloctag(p, getcallerpc(&size)); + return p; +} + +void * +vtbrk(int n) +{ + static Lock lk; + static uchar *buf; + static int nbuf, nchunk; + int align, pad; + void *p; + + if(n >= IdealAlignment) + align = IdealAlignment; + else if(n > 8) + align = 8; + else + align = 4; + + lock(&lk); + pad = (align - (uintptr)buf) & (align-1); + if(n + pad > nbuf) { + buf = vtmallocz(ChunkSize); + nbuf = ChunkSize; + pad = (align - (uintptr)buf) & (align-1); + nchunk++; + } + + assert(n + pad <= nbuf); + + p = buf + pad; + buf += pad + n; + nbuf -= pad + n; + unlock(&lk); + + return p; +} + diff --git a/sys/src/libventi/mkfile b/sys/src/libventi/mkfile new file mode 100755 index 000000000..3862b8756 --- /dev/null +++ b/sys/src/libventi/mkfile @@ -0,0 +1,45 @@ +</$objtype/mkfile + +LIB=/$objtype/lib/libventi.a + +OFILES=\ + cache.$O\ + client.$O\ + conn.$O\ + dial.$O\ + debug.$O\ + dtype.$O\ + entry.$O\ + fcall.$O\ + fcallfmt.$O\ + file.$O\ + hangup.$O\ + log.$O\ + mem.$O\ + packet.$O\ + parsescore.$O\ + queue.$O\ + root.$O\ + rpc.$O\ + scorefmt.$O\ + send.$O\ + server.$O\ + srvhello.$O\ + strdup.$O\ + string.$O\ + time.$O\ + version.$O\ + zero.$O\ + zeroscore.$O\ + +HFILES=\ + /sys/include/venti.h\ + +</sys/src/cmd/mksyslib + +send.$O: queue.h +server.$O: queue.h +queue.$O: queue.h + +CFLAGS=$CFLAGS -I. + diff --git a/sys/src/libventi/packet.acid b/sys/src/libventi/packet.acid new file mode 100755 index 000000000..70fbe058c --- /dev/null +++ b/sys/src/libventi/packet.acid @@ -0,0 +1,1194 @@ +sizeof_1_ = 8; +aggr _1_ +{ + 'U' 0 lo; + 'U' 4 hi; +}; + +defn +_1_(addr) { + complex _1_ addr; + print(" lo ", addr.lo, "\n"); + print(" hi ", addr.hi, "\n"); +}; + +sizeofFPdbleword = 8; +aggr FPdbleword +{ + 'F' 0 x; + { + 'U' 0 lo; + 'U' 4 hi; + }; +}; + +defn +FPdbleword(addr) { + complex FPdbleword addr; + print(" x ", addr.x, "\n"); + print("_1_ {\n"); + _1_(addr+0); + print("}\n"); +}; + +UTFmax = 3; +Runesync = 128; +Runeself = 128; +Runeerror = 65533; +sizeofFmt = 48; +aggr Fmt +{ + 'b' 0 runes; + 'X' 4 start; + 'X' 8 to; + 'X' 12 stop; + 'X' 16 flush; + 'X' 20 farg; + 'D' 24 nfmt; + 'X' 28 args; + 'D' 32 r; + 'D' 36 width; + 'D' 40 prec; + 'U' 44 flags; +}; + +defn +Fmt(addr) { + complex Fmt addr; + print(" runes ", addr.runes, "\n"); + print(" start ", addr.start\X, "\n"); + print(" to ", addr.to\X, "\n"); + print(" stop ", addr.stop\X, "\n"); + print(" flush ", addr.flush\X, "\n"); + print(" farg ", addr.farg\X, "\n"); + print(" nfmt ", addr.nfmt, "\n"); + print(" args ", addr.args\X, "\n"); + print(" r ", addr.r, "\n"); + print(" width ", addr.width, "\n"); + print(" prec ", addr.prec, "\n"); + print(" flags ", addr.flags, "\n"); +}; + +FmtWidth = 1; +FmtLeft = 2; +FmtPrec = 4; +FmtSharp = 8; +FmtSpace = 16; +FmtSign = 32; +FmtZero = 64; +FmtUnsigned = 128; +FmtShort = 256; +FmtLong = 512; +FmtVLong = 1024; +FmtComma = 2048; +FmtByte = 4096; +FmtFlag = 8192; +sizeofTm = 40; +aggr Tm +{ + 'D' 0 sec; + 'D' 4 min; + 'D' 8 hour; + 'D' 12 mday; + 'D' 16 mon; + 'D' 20 year; + 'D' 24 wday; + 'D' 28 yday; + 'a' 32 zone; + 'D' 36 tzoff; +}; + +defn +Tm(addr) { + complex Tm addr; + print(" sec ", addr.sec, "\n"); + print(" min ", addr.min, "\n"); + print(" hour ", addr.hour, "\n"); + print(" mday ", addr.mday, "\n"); + print(" mon ", addr.mon, "\n"); + print(" year ", addr.year, "\n"); + print(" wday ", addr.wday, "\n"); + print(" yday ", addr.yday, "\n"); + print(" zone ", addr.zone, "\n"); + print(" tzoff ", addr.tzoff, "\n"); +}; + +PNPROC = 1; +PNGROUP = 2; +Profoff = 0; +Profuser = 1; +Profkernel = 2; +Proftime = 3; +Profsample = 4; +sizeofLock = 4; +aggr Lock +{ + 'D' 0 val; +}; + +defn +Lock(addr) { + complex Lock addr; + print(" val ", addr.val, "\n"); +}; + +sizeofQLp = 12; +aggr QLp +{ + 'D' 0 inuse; + 'A' QLp 4 next; + 'C' 8 state; +}; + +defn +QLp(addr) { + complex QLp addr; + print(" inuse ", addr.inuse, "\n"); + print(" next ", addr.next\X, "\n"); + print(" state ", addr.state, "\n"); +}; + +sizeofQLock = 16; +aggr QLock +{ + Lock 0 lock; + 'D' 4 locked; + 'A' QLp 8 $head; + 'A' QLp 12 $tail; +}; + +defn +QLock(addr) { + complex QLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" locked ", addr.locked, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofRWLock = 20; +aggr RWLock +{ + Lock 0 lock; + 'D' 4 readers; + 'D' 8 writer; + 'A' QLp 12 $head; + 'A' QLp 16 $tail; +}; + +defn +RWLock(addr) { + complex RWLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" readers ", addr.readers, "\n"); + print(" writer ", addr.writer, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofRendez = 12; +aggr Rendez +{ + 'A' QLock 0 l; + 'A' QLp 4 $head; + 'A' QLp 8 $tail; +}; + +defn +Rendez(addr) { + complex Rendez addr; + print(" l ", addr.l\X, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofNetConnInfo = 36; +aggr NetConnInfo +{ + 'X' 0 dir; + 'X' 4 root; + 'X' 8 spec; + 'X' 12 lsys; + 'X' 16 lserv; + 'X' 20 rsys; + 'X' 24 rserv; + 'X' 28 laddr; + 'X' 32 raddr; +}; + +defn +NetConnInfo(addr) { + complex NetConnInfo addr; + print(" dir ", addr.dir\X, "\n"); + print(" root ", addr.root\X, "\n"); + print(" spec ", addr.spec\X, "\n"); + print(" lsys ", addr.lsys\X, "\n"); + print(" lserv ", addr.lserv\X, "\n"); + print(" rsys ", addr.rsys\X, "\n"); + print(" rserv ", addr.rserv\X, "\n"); + print(" laddr ", addr.laddr\X, "\n"); + print(" raddr ", addr.raddr\X, "\n"); +}; + +RFNAMEG = 1; +RFENVG = 2; +RFFDG = 4; +RFNOTEG = 8; +RFPROC = 16; +RFMEM = 32; +RFNOWAIT = 64; +RFCNAMEG = 1024; +RFCENVG = 2048; +RFCFDG = 4096; +RFREND = 8192; +RFNOMNT = 16384; +sizeofQid = 16; +aggr Qid +{ + 'W' 0 path; + 'U' 8 vers; + 'b' 12 type; +}; + +defn +Qid(addr) { + complex Qid addr; + print(" path ", addr.path, "\n"); + print(" vers ", addr.vers, "\n"); + print(" type ", addr.type, "\n"); +}; + +sizeofDir = 60; +aggr Dir +{ + 'u' 0 type; + 'U' 4 dev; + Qid 8 qid; + 'U' 24 mode; + 'U' 28 atime; + 'U' 32 mtime; + 'V' 36 length; + 'X' 44 name; + 'X' 48 uid; + 'X' 52 gid; + 'X' 56 muid; +}; + +defn +Dir(addr) { + complex Dir addr; + print(" type ", addr.type, "\n"); + print(" dev ", addr.dev, "\n"); + print("Qid qid {\n"); + Qid(addr.qid); + print("}\n"); + print(" mode ", addr.mode, "\n"); + print(" atime ", addr.atime, "\n"); + print(" mtime ", addr.mtime, "\n"); + print(" length ", addr.length, "\n"); + print(" name ", addr.name\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" gid ", addr.gid\X, "\n"); + print(" muid ", addr.muid\X, "\n"); +}; + +sizeofWaitmsg = 20; +aggr Waitmsg +{ + 'D' 0 pid; + 'a' 4 time; + 'X' 16 msg; +}; + +defn +Waitmsg(addr) { + complex Waitmsg addr; + print(" pid ", addr.pid, "\n"); + print(" time ", addr.time, "\n"); + print(" msg ", addr.msg\X, "\n"); +}; + +sizeofIOchunk = 8; +aggr IOchunk +{ + 'X' 0 addr; + 'U' 4 len; +}; + +defn +IOchunk(addr) { + complex IOchunk addr; + print(" addr ", addr.addr\X, "\n"); + print(" len ", addr.len, "\n"); +}; + +MaxFragSize = 9216; +sizeofVtLog = 40; +aggr VtLog +{ + 'A' VtLog 0 next; + 'X' 4 name; + 'X' 8 chunk; + 'U' 12 nchunk; + 'X' 16 w; + QLock 20 lk; + 'D' 36 ref; +}; + +defn +VtLog(addr) { + complex VtLog addr; + print(" next ", addr.next\X, "\n"); + print(" name ", addr.name\X, "\n"); + print(" chunk ", addr.chunk\X, "\n"); + print(" nchunk ", addr.nchunk, "\n"); + print(" w ", addr.w\X, "\n"); + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print(" ref ", addr.ref, "\n"); +}; + +sizeofVtLogChunk = 12; +aggr VtLogChunk +{ + 'X' 0 p; + 'X' 4 ep; + 'X' 8 wp; +}; + +defn +VtLogChunk(addr) { + complex VtLogChunk addr; + print(" p ", addr.p\X, "\n"); + print(" ep ", addr.ep\X, "\n"); + print(" wp ", addr.wp\X, "\n"); +}; + +VtScoreSize = 20; +VtMaxStringSize = 1024; +VtMaxLumpSize = 57344; +VtPointerDepth = 7; +VtDataType = 0; +VtDirType = 8; +VtRootType = 16; +VtMaxType = 17; +VtCorruptType = 255; +VtTypeDepthMask = 7; +VtTypeBaseMask = -8; +VtEntryActive = 1; +_VtEntryDir = 2; +_VtEntryDepthShift = 2; +_VtEntryDepthMask = 28; +VtEntryLocal = 32; +VtEntrySize = 40; +sizeofVtEntry = 40; +aggr VtEntry +{ + 'U' 0 gen; + 'u' 4 psize; + 'u' 6 dsize; + 'b' 8 type; + 'b' 9 flags; + 'W' 12 size; + 'a' 20 score; +}; + +defn +VtEntry(addr) { + complex VtEntry addr; + print(" gen ", addr.gen, "\n"); + print(" psize ", addr.psize, "\n"); + print(" dsize ", addr.dsize, "\n"); + print(" type ", addr.type, "\n"); + print(" flags ", addr.flags, "\n"); + print(" size ", addr.size, "\n"); + print(" score ", addr.score, "\n"); +}; + +sizeofVtRoot = 300; +aggr VtRoot +{ + 'a' 0 name; + 'a' 128 type; + 'a' 256 score; + 'u' 276 blocksize; + 'a' 278 prev; +}; + +defn +VtRoot(addr) { + complex VtRoot addr; + print(" name ", addr.name, "\n"); + print(" type ", addr.type, "\n"); + print(" score ", addr.score, "\n"); + print(" blocksize ", addr.blocksize, "\n"); + print(" prev ", addr.prev, "\n"); +}; + +VtRootSize = 300; +VtRootVersion = 2; +VtCryptoStrengthNone = 0; +VtCryptoStrengthAuth = 1; +VtCryptoStrengthWeak = 2; +VtCryptoStrengthStrong = 3; +VtCryptoNone = 0; +VtCryptoSSL3 = 1; +VtCryptoTLS1 = 2; +VtCryptoMax = 3; +VtCodecNone = 0; +VtCodecDeflate = 1; +VtCodecThwack = 2; +VtCodecMax = 3; +VtRerror = 1; +VtTping = 2; +VtRping = 3; +VtThello = 4; +VtRhello = 5; +VtTgoodbye = 6; +VtRgoodbye = 7; +VtTauth0 = 8; +VtRauth0 = 9; +VtTauth1 = 10; +VtRauth1 = 11; +VtTread = 12; +VtRread = 13; +VtTwrite = 14; +VtRwrite = 15; +VtTsync = 16; +VtRsync = 17; +VtTmax = 18; +sizeofVtFcall = 80; +aggr VtFcall +{ + 'b' 0 msgtype; + 'b' 1 tag; + 'X' 4 error; + 'X' 8 version; + 'X' 12 uid; + 'b' 16 strength; + 'X' 20 crypto; + 'U' 24 ncrypto; + 'X' 28 codec; + 'U' 32 ncodec; + 'X' 36 sid; + 'b' 40 rcrypto; + 'b' 41 rcodec; + 'X' 44 auth; + 'U' 48 nauth; + 'a' 52 score; + 'b' 72 blocktype; + 'u' 74 count; + 'X' 76 data; +}; + +defn +VtFcall(addr) { + complex VtFcall addr; + print(" msgtype ", addr.msgtype, "\n"); + print(" tag ", addr.tag, "\n"); + print(" error ", addr.error\X, "\n"); + print(" version ", addr.version\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" strength ", addr.strength, "\n"); + print(" crypto ", addr.crypto\X, "\n"); + print(" ncrypto ", addr.ncrypto, "\n"); + print(" codec ", addr.codec\X, "\n"); + print(" ncodec ", addr.ncodec, "\n"); + print(" sid ", addr.sid\X, "\n"); + print(" rcrypto ", addr.rcrypto, "\n"); + print(" rcodec ", addr.rcodec, "\n"); + print(" auth ", addr.auth\X, "\n"); + print(" nauth ", addr.nauth, "\n"); + print(" score ", addr.score, "\n"); + print(" blocktype ", addr.blocktype, "\n"); + print(" count ", addr.count, "\n"); + print(" data ", addr.data\X, "\n"); +}; + +VtStateAlloc = 0; +VtStateConnected = 1; +VtStateClosed = 2; +sizeofVtConn = 1404; +aggr VtConn +{ + QLock 0 lk; + QLock 16 inlk; + QLock 32 outlk; + 'D' 48 debug; + 'D' 52 infd; + 'D' 56 outfd; + 'D' 60 muxer; + 'X' 64 writeq; + 'X' 68 readq; + 'D' 72 state; + 'a' 76 wait; + 'U' 1100 ntag; + 'U' 1104 nsleep; + 'X' 1108 part; + Rendez 1112 tagrend; + Rendez 1124 rpcfork; + 'X' 1136 version; + 'X' 1140 uid; + 'X' 1144 sid; + 'a' 1148 addr; +}; + +defn +VtConn(addr) { + complex VtConn addr; + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print("QLock inlk {\n"); + QLock(addr.inlk); + print("}\n"); + print("QLock outlk {\n"); + QLock(addr.outlk); + print("}\n"); + print(" debug ", addr.debug, "\n"); + print(" infd ", addr.infd, "\n"); + print(" outfd ", addr.outfd, "\n"); + print(" muxer ", addr.muxer, "\n"); + print(" writeq ", addr.writeq\X, "\n"); + print(" readq ", addr.readq\X, "\n"); + print(" state ", addr.state, "\n"); + print(" wait ", addr.wait, "\n"); + print(" ntag ", addr.ntag, "\n"); + print(" nsleep ", addr.nsleep, "\n"); + print(" part ", addr.part\X, "\n"); + print("Rendez tagrend {\n"); + Rendez(addr.tagrend); + print("}\n"); + print("Rendez rpcfork {\n"); + Rendez(addr.rpcfork); + print("}\n"); + print(" version ", addr.version\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" sid ", addr.sid\X, "\n"); + print(" addr ", addr.addr, "\n"); +}; + +sizeofVtReq = 168; +aggr VtReq +{ + VtFcall 0 tx; + VtFcall 80 rx; + 'X' 160 srv; + 'X' 164 sc; +}; + +defn +VtReq(addr) { + complex VtReq addr; + print("VtFcall tx {\n"); + VtFcall(addr.tx); + print("}\n"); + print("VtFcall rx {\n"); + VtFcall(addr.rx); + print("}\n"); + print(" srv ", addr.srv\X, "\n"); + print(" sc ", addr.sc\X, "\n"); +}; + +NilBlock = -1; +sizeofVtBlock = 84; +aggr VtBlock +{ + 'X' 0 c; + QLock 4 lk; + 'X' 20 data; + 'a' 24 score; + 'b' 44 type; + 'D' 48 nlock; + 'D' 52 iostate; + 'D' 56 ref; + 'U' 60 heap; + 'A' VtBlock 64 next; + 'A' VtBlock 68 prev; + 'U' 72 used; + 'U' 76 used2; + 'U' 80 addr; +}; + +defn +VtBlock(addr) { + complex VtBlock addr; + print(" c ", addr.c\X, "\n"); + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print(" data ", addr.data\X, "\n"); + print(" score ", addr.score, "\n"); + print(" type ", addr.type, "\n"); + print(" nlock ", addr.nlock, "\n"); + print(" iostate ", addr.iostate, "\n"); + print(" ref ", addr.ref, "\n"); + print(" heap ", addr.heap, "\n"); + print(" next ", addr.next\X, "\n"); + print(" prev ", addr.prev\X, "\n"); + print(" used ", addr.used, "\n"); + print(" used2 ", addr.used2, "\n"); + print(" addr ", addr.addr, "\n"); +}; + +sizeofVtFile = 84; +aggr VtFile +{ + QLock 0 lk; + 'D' 16 ref; + 'D' 20 $local; + 'A' VtBlock 24 b; + 'a' 28 score; + 'X' 48 c; + 'D' 52 mode; + 'U' 56 gen; + 'D' 60 dsize; + 'D' 64 psize; + 'D' 68 dir; + 'A' VtFile 72 parent; + 'D' 76 epb; + 'U' 80 offset; +}; + +defn +VtFile(addr) { + complex VtFile addr; + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print(" ref ", addr.ref, "\n"); + print(" $local ", addr.$local, "\n"); + print(" b ", addr.b\X, "\n"); + print(" score ", addr.score, "\n"); + print(" c ", addr.c\X, "\n"); + print(" mode ", addr.mode, "\n"); + print(" gen ", addr.gen, "\n"); + print(" dsize ", addr.dsize, "\n"); + print(" psize ", addr.psize, "\n"); + print(" dir ", addr.dir, "\n"); + print(" parent ", addr.parent\X, "\n"); + print(" epb ", addr.epb, "\n"); + print(" offset ", addr.offset, "\n"); +}; + +VtOREAD = 0; +VtOWRITE = 1; +VtORDWR = 2; +AESbsize = 16; +AESmaxkey = 32; +AESmaxrounds = 14; +sizeofAESstate = 540; +aggr AESstate +{ + 'U' 0 setup; + 'D' 4 rounds; + 'D' 8 keybytes; + 'a' 12 key; + 'a' 44 ekey; + 'a' 284 dkey; + 'a' 524 ivec; +}; + +defn +AESstate(addr) { + complex AESstate addr; + print(" setup ", addr.setup, "\n"); + print(" rounds ", addr.rounds, "\n"); + print(" keybytes ", addr.keybytes, "\n"); + print(" key ", addr.key, "\n"); + print(" ekey ", addr.ekey, "\n"); + print(" dkey ", addr.dkey, "\n"); + print(" ivec ", addr.ivec, "\n"); +}; + +BFbsize = 8; +BFrounds = 16; +sizeofBFstate = 4236; +aggr BFstate +{ + 'U' 0 setup; + 'a' 4 key; + 'a' 60 ivec; + 'a' 68 pbox; + 'a' 140 sbox; +}; + +defn +BFstate(addr) { + complex BFstate addr; + print(" setup ", addr.setup, "\n"); + print(" key ", addr.key, "\n"); + print(" ivec ", addr.ivec, "\n"); + print(" pbox ", addr.pbox, "\n"); + print(" sbox ", addr.sbox, "\n"); +}; + +DESbsize = 8; +sizeofDESstate = 148; +aggr DESstate +{ + 'U' 0 setup; + 'a' 4 key; + 'a' 12 expanded; + 'a' 140 ivec; +}; + +defn +DESstate(addr) { + complex DESstate addr; + print(" setup ", addr.setup, "\n"); + print(" key ", addr.key, "\n"); + print(" expanded ", addr.expanded, "\n"); + print(" ivec ", addr.ivec, "\n"); +}; + +DES3E = 0; +DES3D = 1; +DES3EEE = 0; +DES3EDE = 2; +DES3DED = 5; +DES3DDD = 7; +sizeofDES3state = 420; +aggr DES3state +{ + 'U' 0 setup; + 'a' 4 key; + 'a' 28 expanded; + 'a' 412 ivec; +}; + +defn +DES3state(addr) { + complex DES3state addr; + print(" setup ", addr.setup, "\n"); + print(" key ", addr.key, "\n"); + print(" expanded ", addr.expanded, "\n"); + print(" ivec ", addr.ivec, "\n"); +}; + +SHA1dlen = 20; +MD4dlen = 16; +MD5dlen = 16; +sizeofDigestState = 164; +aggr DigestState +{ + 'W' 0 len; + 'a' 8 state; + 'a' 28 buf; + 'D' 156 blen; + 'C' 160 malloced; + 'C' 161 seeded; +}; + +defn +DigestState(addr) { + complex DigestState addr; + print(" len ", addr.len, "\n"); + print(" state ", addr.state, "\n"); + print(" buf ", addr.buf, "\n"); + print(" blen ", addr.blen, "\n"); + print(" malloced ", addr.malloced, "\n"); + print(" seeded ", addr.seeded, "\n"); +}; + +sizeofRC4state = 260; +aggr RC4state +{ + 'a' 0 state; + 'b' 256 x; + 'b' 257 y; +}; + +defn +RC4state(addr) { + complex RC4state addr; + print(" state ", addr.state, "\n"); + print(" x ", addr.x, "\n"); + print(" y ", addr.y, "\n"); +}; + +sizeofRSApub = 8; +aggr RSApub +{ + 'X' 0 n; + 'X' 4 ek; +}; + +defn +RSApub(addr) { + complex RSApub addr; + print(" n ", addr.n\X, "\n"); + print(" ek ", addr.ek\X, "\n"); +}; + +sizeofRSApriv = 32; +aggr RSApriv +{ + RSApub 0 pub; + 'X' 8 dk; + 'X' 12 p; + 'X' 16 q; + 'X' 20 kp; + 'X' 24 kq; + 'X' 28 c2; +}; + +defn +RSApriv(addr) { + complex RSApriv addr; + print("RSApub pub {\n"); + RSApub(addr.pub); + print("}\n"); + print(" dk ", addr.dk\X, "\n"); + print(" p ", addr.p\X, "\n"); + print(" q ", addr.q\X, "\n"); + print(" kp ", addr.kp\X, "\n"); + print(" kq ", addr.kq\X, "\n"); + print(" c2 ", addr.c2\X, "\n"); +}; + +sizeofPEMChain = 12; +aggr PEMChain +{ + 'A' PEMChain 0 next; + 'X' 4 pem; + 'D' 8 pemlen; +}; + +defn +PEMChain(addr) { + complex PEMChain addr; + print(" next ", addr.next\X, "\n"); + print(" pem ", addr.pem\X, "\n"); + print(" pemlen ", addr.pemlen, "\n"); +}; + +sizeofEGpub = 12; +aggr EGpub +{ + 'X' 0 p; + 'X' 4 alpha; + 'X' 8 key; +}; + +defn +EGpub(addr) { + complex EGpub addr; + print(" p ", addr.p\X, "\n"); + print(" alpha ", addr.alpha\X, "\n"); + print(" key ", addr.key\X, "\n"); +}; + +sizeofEGpriv = 16; +aggr EGpriv +{ + EGpub 0 pub; + 'X' 12 secret; +}; + +defn +EGpriv(addr) { + complex EGpriv addr; + print("EGpub pub {\n"); + EGpub(addr.pub); + print("}\n"); + print(" secret ", addr.secret\X, "\n"); +}; + +sizeofEGsig = 8; +aggr EGsig +{ + 'X' 0 r; + 'X' 4 s; +}; + +defn +EGsig(addr) { + complex EGsig addr; + print(" r ", addr.r\X, "\n"); + print(" s ", addr.s\X, "\n"); +}; + +sizeofDSApub = 16; +aggr DSApub +{ + 'X' 0 p; + 'X' 4 q; + 'X' 8 alpha; + 'X' 12 key; +}; + +defn +DSApub(addr) { + complex DSApub addr; + print(" p ", addr.p\X, "\n"); + print(" q ", addr.q\X, "\n"); + print(" alpha ", addr.alpha\X, "\n"); + print(" key ", addr.key\X, "\n"); +}; + +sizeofDSApriv = 20; +aggr DSApriv +{ + DSApub 0 pub; + 'X' 16 secret; +}; + +defn +DSApriv(addr) { + complex DSApriv addr; + print("DSApub pub {\n"); + DSApub(addr.pub); + print("}\n"); + print(" secret ", addr.secret\X, "\n"); +}; + +sizeofDSAsig = 8; +aggr DSAsig +{ + 'X' 0 r; + 'X' 4 s; +}; + +defn +DSAsig(addr) { + complex DSAsig addr; + print(" r ", addr.r\X, "\n"); + print(" s ", addr.s\X, "\n"); +}; + +sizeofThumbprint = 24; +aggr Thumbprint +{ + 'A' Thumbprint 0 next; + 'a' 4 sha1; +}; + +defn +Thumbprint(addr) { + complex Thumbprint addr; + print(" next ", addr.next\X, "\n"); + print(" sha1 ", addr.sha1, "\n"); +}; + +sizeofTLSconn = 80; +aggr TLSconn +{ + 'a' 0 dir; + 'X' 40 cert; + 'X' 44 sessionID; + 'D' 48 certlen; + 'D' 52 sessionIDlen; + 'X' 56 trace; + 'A' PEMChain 60 chain; + 'X' 64 sessionType; + 'X' 68 sessionKey; + 'D' 72 sessionKeylen; + 'X' 76 sessionConst; +}; + +defn +TLSconn(addr) { + complex TLSconn addr; + print(" dir ", addr.dir, "\n"); + print(" cert ", addr.cert\X, "\n"); + print(" sessionID ", addr.sessionID\X, "\n"); + print(" certlen ", addr.certlen, "\n"); + print(" sessionIDlen ", addr.sessionIDlen, "\n"); + print(" trace ", addr.trace\X, "\n"); + print(" chain ", addr.chain\X, "\n"); + print(" sessionType ", addr.sessionType\X, "\n"); + print(" sessionKey ", addr.sessionKey\X, "\n"); + print(" sessionKeylen ", addr.sessionKeylen, "\n"); + print(" sessionConst ", addr.sessionConst\X, "\n"); +}; + +BigMemSize = 9216; +SmallMemSize = 1152; +NLocalFrag = 2; +PFront = 0; +PMiddle = 1; +PEnd = 2; +sizeofMem = 28; +aggr Mem +{ + Lock 0 lk; + 'D' 4 ref; + 'X' 8 bp; + 'X' 12 ep; + 'X' 16 rp; + 'X' 20 wp; + 'A' Mem 24 next; +}; + +defn +Mem(addr) { + complex Mem addr; + print("Lock lk {\n"); + Lock(addr.lk); + print("}\n"); + print(" ref ", addr.ref, "\n"); + print(" bp ", addr.bp\X, "\n"); + print(" ep ", addr.ep\X, "\n"); + print(" rp ", addr.rp\X, "\n"); + print(" wp ", addr.wp\X, "\n"); + print(" next ", addr.next\X, "\n"); +}; + +FragLocalFree = 0; +FragLocalAlloc = 1; +FragGlobal = 2; +sizeofFrag = 32; +aggr Frag +{ + 'D' 0 state; + 'A' Mem 4 mem; + 'X' 8 rp; + 'X' 12 wp; + 'A' Frag 16 next; + 'X' 20 free; + 'X' 24 a; + 'X' 28 p; +}; + +defn +Frag(addr) { + complex Frag addr; + print(" state ", addr.state, "\n"); + print(" mem ", addr.mem\X, "\n"); + print(" rp ", addr.rp\X, "\n"); + print(" wp ", addr.wp\X, "\n"); + print(" next ", addr.next\X, "\n"); + print(" free ", addr.free\X, "\n"); + print(" a ", addr.a\X, "\n"); + print(" p ", addr.p\X, "\n"); +}; + +sizeofPacket = 88; +aggr Packet +{ + 'D' 0 size; + 'D' 4 asize; + 'U' 8 pc; + 'A' Packet 12 next; + 'A' Frag 16 first; + 'A' Frag 20 last; + 'a' 24 $local; +}; + +defn +Packet(addr) { + complex Packet addr; + print(" size ", addr.size, "\n"); + print(" asize ", addr.asize, "\n"); + print(" pc ", addr.pc, "\n"); + print(" next ", addr.next\X, "\n"); + print(" first ", addr.first\X, "\n"); + print(" last ", addr.last\X, "\n"); + print(" $local ", addr.$local, "\n"); +}; + +sizeof_2_ = 36; +aggr _2_ +{ + Lock 0 lk; + 'A' Packet 4 packet; + 'D' 8 npacket; + 'A' Frag 12 frag; + 'D' 16 nfrag; + 'A' Mem 20 bigmem; + 'D' 24 nbigmem; + 'A' Mem 28 smallmem; + 'D' 32 nsmallmem; +}; + +defn +_2_(addr) { + complex _2_ addr; + print("Lock lk {\n"); + Lock(addr.lk); + print("}\n"); + print(" packet ", addr.packet\X, "\n"); + print(" npacket ", addr.npacket, "\n"); + print(" frag ", addr.frag\X, "\n"); + print(" nfrag ", addr.nfrag, "\n"); + print(" bigmem ", addr.bigmem\X, "\n"); + print(" nbigmem ", addr.nbigmem, "\n"); + print(" smallmem ", addr.smallmem\X, "\n"); + print(" nsmallmem ", addr.nsmallmem, "\n"); +}; + +complex _2_ freelist; +complex Packet packetalloc:p; +complex Packet packetfree:p; +complex Frag packetfree:f; +complex Frag packetfree:ff; +complex Packet packetdup:p; +complex Frag packetdup:f; +complex Frag packetdup:ff; +complex Packet packetdup:pp; +complex Packet packetsplit:p; +complex Packet packetsplit:pp; +complex Frag packetsplit:f; +complex Frag packetsplit:ff; +complex Packet packetconsume:p; +complex Packet packettrim:p; +complex Frag packettrim:f; +complex Frag packettrim:ff; +complex Packet packetheader:p; +complex Frag packetheader:f; +complex Mem packetheader:m; +complex Packet packettrailer:p; +complex Mem packettrailer:m; +complex Frag packettrailer:f; +complex Packet packetprefix:p; +complex Frag packetprefix:f; +complex Mem packetprefix:m; +complex Packet packetappend:p; +complex Frag packetappend:f; +complex Mem packetappend:m; +complex Packet packetconcat:p; +complex Packet packetconcat:pp; +complex Frag packetconcat:f; +complex Packet packetpeek:p; +complex Frag packetpeek:f; +complex Packet packetcopy:p; +complex Packet packetfragments:p; +complex IOchunk packetfragments:io; +complex Frag packetfragments:f; +complex IOchunk packetfragments:eio; +complex Packet packetstats:p; +complex Frag packetstats:f; +complex Mem packetstats:m; +complex Packet packetsize:p; +complex Frag packetsize:f; +complex Packet packetasize:p; +complex Frag packetasize:f; +complex Packet packetsha1:p; +complex DigestState packetsha1:ds; +complex Frag packetsha1:f; +complex Packet packetcmp:pkt0; +complex Packet packetcmp:pkt1; +complex Frag packetcmp:f0; +complex Frag packetcmp:f1; +complex Packet fragalloc:p; +complex Frag fragalloc:next; +complex Frag fragalloc:f; +complex Frag fragalloc:ef; +complex Mem fragalloc:m; +complex Packet packetforeign:p; +complex Frag packetforeign:f; +complex Packet fragdup:p; +complex Frag fragdup:f; +complex Frag fragdup:ff; +complex Mem fragdup:m; +complex Frag fragfree:f; +complex Mem memalloc:m; +complex Mem memfree:m; +complex Mem memhead:m; +complex Mem memtail:m; diff --git a/sys/src/libventi/packet.c b/sys/src/libventi/packet.c new file mode 100755 index 000000000..d19d85371 --- /dev/null +++ b/sys/src/libventi/packet.c @@ -0,0 +1,1025 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> +#include <libsec.h> + +typedef struct Mem Mem; +typedef struct Frag Frag; + +enum { + BigMemSize = MaxFragSize, + SmallMemSize = BigMemSize/8, + NLocalFrag = 2 +}; + +/* position to carve out of a Mem */ +enum { + PFront, + PMiddle, + PEnd +}; + +struct Mem +{ + Lock lk; + int ref; + uchar *bp; + uchar *ep; + uchar *rp; + uchar *wp; + Mem *next; +}; + +enum { + FragLocalFree, + FragLocalAlloc, + FragGlobal +}; + +struct Frag +{ + int state; + Mem *mem; + uchar *rp; + uchar *wp; + Frag *next; + void (*free)(void*); + void *a; + Packet *p; /* parent packet, for debugging only */ +}; + +struct Packet +{ + int size; + int asize; /* allocated memory - greater than size unless foreign frags */ + ulong pc; + + Packet *next; + + Frag *first; + Frag *last; + + Frag local[NLocalFrag]; +}; + +static Frag *fragalloc(Packet*, int n, int pos, Frag *next); +static Frag *fragdup(Packet*, Frag*); +static void fragfree(Frag*); + +static Mem *memalloc(int, int); +static void memfree(Mem*); +static int memhead(Mem *m, uchar *rp, int n); +static int memtail(Mem *m, uchar *wp, int n); + +static char EPacketSize[] = "bad packet size"; +static char EPacketOffset[] = "bad packet offset"; +static char EBadSize[] = "bad size"; + +#ifdef NOTDEF +static void checkpacket(Packet*); +#endif + +/* + * the free list is primarily for speed, but it is + * also necessary for packetsplit that packets + * are never freed -- a packet can contain a different + * packet's local fragments, thanks to packetsplit! + */ +static struct { + Lock lk; + Packet *packet; + int npacket; + Frag *frag; + int nfrag; + Mem *bigmem; + int nbigmem; + Mem *smallmem; + int nsmallmem; +} freelist; + +#define FRAGSIZE(f) ((f)->wp - (f)->rp) +#define FRAGASIZE(f) ((f)->mem ? (f)->mem->ep - (f)->mem->bp : 0) + +#define NOTFREE(p) assert((p)->size>=0)/*; checkpacket(p)*/ + +Packet * +packetalloc(void) +{ + Packet *p; + + lock(&freelist.lk); + p = freelist.packet; + if(p != nil) + freelist.packet = p->next; + else + freelist.npacket++; + unlock(&freelist.lk); + + if(p == nil) + p = vtbrk(sizeof(Packet)); + else + assert(p->size == -1); + p->size = 0; + p->asize = 0; + p->first = nil; + p->last = nil; + p->next = nil; + p->pc = getcallerpc((char*)&p+8); /* might not work, but fine */ + + NOTFREE(p); + return p; +} + +void +packetfree(Packet *p) +{ + Frag *f, *ff; + + if(p == nil) + return; + + NOTFREE(p); + p->pc = getcallerpc(&p); + + for(f=p->first; f!=nil; f=ff) { + ff = f->next; + fragfree(f); + } + p->first = (void*)0xDeadBeef; + p->last = (void*)0xDeadBeef; + p->size = -1; + + lock(&freelist.lk); + p->next = freelist.packet; + freelist.packet = p; + unlock(&freelist.lk); +} + +Packet * +packetdup(Packet *p, int offset, int n) +{ + Frag *f, *ff; + Packet *pp; + + NOTFREE(p); + if(offset < 0 || n < 0 || offset+n > p->size) { + werrstr(EBadSize); + return nil; + } + + pp = packetalloc(); + pp->pc = getcallerpc(&p); + if(n == 0){ + NOTFREE(pp); + return pp; + } + + pp->size = n; + + /* skip offset */ + for(f=p->first; offset >= FRAGSIZE(f); f=f->next) + offset -= FRAGSIZE(f); + + /* first frag */ + ff = fragdup(pp, f); + ff->rp += offset; + pp->first = ff; + n -= FRAGSIZE(ff); + pp->asize += FRAGASIZE(ff); + + /* the remaining */ + while(n > 0) { + f = f->next; + ff->next = fragdup(pp, f); + ff = ff->next; + n -= FRAGSIZE(ff); + pp->asize += FRAGASIZE(ff); + } + + /* fix up last frag: note n <= 0 */ + ff->wp += n; + ff->next = nil; + pp->last = ff; + + NOTFREE(pp); + NOTFREE(p); + return pp; +} + +Packet * +packetsplit(Packet *p, int n) +{ + Packet *pp; + Frag *f, *ff; + + NOTFREE(p); + if(n < 0 || n > p->size) { + werrstr(EPacketSize); + return nil; + } + + pp = packetalloc(); + pp->pc = getcallerpc(&p); + if(n == 0){ + NOTFREE(pp); + return pp; + } + + pp->size = n; + p->size -= n; + ff = nil; + for(f=p->first; n > 0 && n >= FRAGSIZE(f); f=f->next) { + n -= FRAGSIZE(f); + p->asize -= FRAGASIZE(f); + pp->asize += FRAGASIZE(f); + f->p = pp; + ff = f; + } + + /* split shared frag */ + if(n > 0) { + f->p = pp; + ff = f; + f = fragdup(p, ff); + pp->asize += FRAGASIZE(ff); + ff->wp = ff->rp + n; + f->rp += n; + } + + pp->first = p->first; + pp->last = ff; + ff->next = nil; + p->first = f; + if(f == nil || f->next == nil) + p->last = f; + NOTFREE(pp); + NOTFREE(p); + return pp; +} + +int +packetconsume(Packet *p, uchar *buf, int n) +{ + NOTFREE(p); + if(buf && packetcopy(p, buf, 0, n) < 0) + return -1; + return packettrim(p, n, p->size-n); +} + +int +packettrim(Packet *p, int offset, int n) +{ + Frag *f, *ff; + + NOTFREE(p); + if(offset < 0 || offset > p->size) { + werrstr(EPacketOffset); + return -1; + } + + if(n < 0 || offset + n > p->size) { + werrstr(EPacketOffset); + return -1; + } + + p->size = n; + + /* easy case */ + if(n == 0) { + for(f=p->first; f != nil; f=ff) { + ff = f->next; + fragfree(f); + } + p->first = p->last = nil; + p->asize = 0; + NOTFREE(p); + return 0; + } + + /* free before offset */ + for(f=p->first; offset >= FRAGSIZE(f); f=ff) { + p->asize -= FRAGASIZE(f); + offset -= FRAGSIZE(f); + ff = f->next; + fragfree(f); + } + + /* adjust frag */ + f->rp += offset; + p->first = f; + + /* skip middle */ + for(; n > 0 && n > FRAGSIZE(f); f=f->next) + n -= FRAGSIZE(f); + + /* adjust end */ + f->wp = f->rp + n; + p->last = f; + ff = f->next; + f->next = nil; + + /* free after */ + for(f=ff; f != nil; f=ff) { + p->asize -= FRAGASIZE(f); + ff = f->next; + fragfree(f); + } + NOTFREE(p); + return 0; +} + +uchar * +packetheader(Packet *p, int n) +{ + Frag *f; + Mem *m; + + NOTFREE(p); + if(n <= 0 || n > MaxFragSize) { + werrstr(EPacketSize); + return nil; + } + + p->size += n; + + /* try and fix in current frag */ + f = p->first; + if(f != nil) { + m = f->mem; + if(n <= f->rp - m->bp) + if(m->ref == 1 || memhead(m, f->rp, n) >= 0) { + f->rp -= n; + NOTFREE(p); + return f->rp; + } + } + + /* add frag to front */ + f = fragalloc(p, n, PEnd, p->first); + p->asize += FRAGASIZE(f); + if(p->first == nil) + p->last = f; + p->first = f; + NOTFREE(p); + return f->rp; +} + +uchar * +packettrailer(Packet *p, int n) +{ + Mem *m; + Frag *f; + + NOTFREE(p); + if(n <= 0 || n > MaxFragSize) { + werrstr(EPacketSize); + return nil; + } + + p->size += n; + + /* try and fix in current frag */ + if(p->first != nil) { + f = p->last; + m = f->mem; + if(n <= m->ep - f->wp) + if(m->ref == 1 || memtail(m, f->wp, n) >= 0) { + f->wp += n; + NOTFREE(p); + return f->wp - n; + } + } + + /* add frag to end */ + f = fragalloc(p, n, (p->first == nil)?PMiddle:PFront, nil); + p->asize += FRAGASIZE(f); + if(p->first == nil) + p->first = f; + else + p->last->next = f; + p->last = f; + NOTFREE(p); + return f->rp; +} + +void +packetprefix(Packet *p, uchar *buf, int n) +{ + Frag *f; + int nn; + Mem *m; + + NOTFREE(p); + if(n <= 0) + return; + + p->size += n; + + /* try and fix in current frag */ + f = p->first; + if(f != nil) { + m = f->mem; + nn = f->rp - m->bp; + if(nn > n) + nn = n; + if(m->ref == 1 || memhead(m, f->rp, nn) >= 0) { + f->rp -= nn; + n -= nn; + memmove(f->rp, buf+n, nn); + } + } + + while(n > 0) { + nn = n; + if(nn > MaxFragSize) + nn = MaxFragSize; + f = fragalloc(p, nn, PEnd, p->first); + p->asize += FRAGASIZE(f); + if(p->first == nil) + p->last = f; + p->first = f; + n -= nn; + memmove(f->rp, buf+n, nn); + } + NOTFREE(p); +} + +void +packetappend(Packet *p, uchar *buf, int n) +{ + Frag *f; + int nn; + Mem *m; + + NOTFREE(p); + if(n <= 0) + return; + + p->size += n; + /* try and fix in current frag */ + if(p->first != nil) { + f = p->last; + m = f->mem; + nn = m->ep - f->wp; + if(nn > n) + nn = n; + if(m->ref == 1 || memtail(m, f->wp, nn) >= 0) { + memmove(f->wp, buf, nn); + f->wp += nn; + buf += nn; + n -= nn; + } + } + + while(n > 0) { + nn = n; + if(nn > MaxFragSize) + nn = MaxFragSize; + f = fragalloc(p, nn, (p->first == nil)?PMiddle:PFront, nil); + p->asize += FRAGASIZE(f); + if(p->first == nil) + p->first = f; + else + p->last->next = f; + p->last = f; + memmove(f->rp, buf, nn); + buf += nn; + n -= nn; + } + NOTFREE(p); +} + +void +packetconcat(Packet *p, Packet *pp) +{ + Frag *f; + + NOTFREE(p); + NOTFREE(pp); + if(pp->size == 0) + return; + p->size += pp->size; + p->asize += pp->asize; + for(f=pp->first; f; f=f->next) + f->p = p; + + if(p->first != nil) + p->last->next = pp->first; + else + p->first = pp->first; + + p->last = pp->last; + pp->size = 0; + pp->asize = 0; + pp->first = nil; + pp->last = nil; + NOTFREE(p); + NOTFREE(pp); +} + +uchar * +packetpeek(Packet *p, uchar *buf, int offset, int n) +{ + Frag *f; + int nn; + uchar *b; + + NOTFREE(p); + if(n == 0) + return buf; + + if(offset < 0 || offset >= p->size) { + werrstr(EPacketOffset); + return nil; + } + + if(n < 0 || offset + n > p->size) { + werrstr(EPacketSize); + return nil; + } + + /* skip up to offset */ + for(f=p->first; offset >= FRAGSIZE(f); f=f->next) + offset -= FRAGSIZE(f); + + /* easy case */ + if(offset + n <= FRAGSIZE(f)){ + NOTFREE(p); + return f->rp + offset; + } + + for(b=buf; n>0; n -= nn) { + nn = FRAGSIZE(f) - offset; + if(nn > n) + nn = n; + memmove(b, f->rp+offset, nn); + offset = 0; + f = f->next; + b += nn; + } + + NOTFREE(p); + return buf; +} + +int +packetcopy(Packet *p, uchar *buf, int offset, int n) +{ + uchar *b; + + NOTFREE(p); + b = packetpeek(p, buf, offset, n); + if(b == nil) + return -1; + if(b != buf) + memmove(buf, b, n); + return 0; +} + +int +packetfragments(Packet *p, IOchunk *io, int nio, int offset) +{ + Frag *f; + int size; + IOchunk *eio; + + NOTFREE(p); + if(p->size == 0 || nio <= 0) + return 0; + + if(offset < 0 || offset > p->size) { + werrstr(EPacketOffset); + return -1; + } + + for(f=p->first; offset >= FRAGSIZE(f); f=f->next) + offset -= FRAGSIZE(f); + + size = 0; + eio = io + nio; + for(; f != nil && io < eio; f=f->next) { + io->addr = f->rp + offset; + io->len = f->wp - (f->rp + offset); + offset = 0; + size += io->len; + io++; + } + for(; io < eio; io++){ + io->addr = nil; + io->len = 0; + } + return size; +} + +void +packetstats(void) +{ + Packet *p; + Frag *f; + Mem *m; + + int np, nf, nsm, nbm; + + lock(&freelist.lk); + np = 0; + for(p=freelist.packet; p; p=p->next) + np++; + nf = 0; + for(f=freelist.frag; f; f=f->next) + nf++; + nsm = 0; + for(m=freelist.smallmem; m; m=m->next) + nsm++; + nbm = 0; + for(m=freelist.bigmem; m; m=m->next) + nbm++; + + fprint(2, "packet: %d/%d frag: %d/%d small mem: %d/%d big mem: %d/%d\n", + np, freelist.npacket, + nf, freelist.nfrag, + nsm, freelist.nsmallmem, + nbm, freelist.nbigmem); + + unlock(&freelist.lk); +} + + +uint +packetsize(Packet *p) +{ + NOTFREE(p); + if(1) { + Frag *f; + int size = 0; + + for(f=p->first; f; f=f->next) + size += FRAGSIZE(f); + if(size != p->size) + fprint(2, "packetsize %d %d\n", size, p->size); + assert(size == p->size); + } + return p->size; +} + +uint +packetasize(Packet *p) +{ + NOTFREE(p); + if(0) { + Frag *f; + int asize = 0; + + for(f=p->first; f; f=f->next) + asize += FRAGASIZE(f); + if(asize != p->asize) + fprint(2, "packetasize %d %d\n", asize, p->asize); + assert(asize == p->asize); + } + return p->asize; +} + +void +packetsha1(Packet *p, uchar digest[VtScoreSize]) +{ + DigestState ds; + Frag *f; + int size; + + NOTFREE(p); + memset(&ds, 0, sizeof ds); + size = p->size; + for(f=p->first; f; f=f->next) { + sha1(f->rp, FRAGSIZE(f), nil, &ds); + size -= FRAGSIZE(f); + } + assert(size == 0); + sha1(nil, 0, digest, &ds); +} + +int +packetcmp(Packet *pkt0, Packet *pkt1) +{ + Frag *f0, *f1; + int n0, n1, x; + + NOTFREE(pkt0); + NOTFREE(pkt1); + f0 = pkt0->first; + f1 = pkt1->first; + + if(f0 == nil) + return (f1 == nil)?0:-1; + if(f1 == nil) + return 1; + n0 = FRAGSIZE(f0); + n1 = FRAGSIZE(f1); + + for(;;) { + if(n0 < n1) { + x = memcmp(f0->wp - n0, f1->wp - n1, n0); + if(x != 0) + return x; + n1 -= n0; + f0 = f0->next; + if(f0 == nil) + return -1; + n0 = FRAGSIZE(f0); + } else if (n0 > n1) { + x = memcmp(f0->wp - n0, f1->wp - n1, n1); + if(x != 0) + return x; + n0 -= n1; + f1 = f1->next; + if(f1 == nil) + return 1; + n1 = FRAGSIZE(f1); + } else { /* n0 == n1 */ + x = memcmp(f0->wp - n0, f1->wp - n1, n0); + if(x != 0) + return x; + f0 = f0->next; + f1 = f1->next; + if(f0 == nil) + return (f1 == nil)?0:-1; + if(f1 == nil) + return 1; + n0 = FRAGSIZE(f0); + n1 = FRAGSIZE(f1); + } + } +} + +static Frag * +fragalloc(Packet *p, int n, int pos, Frag *next) +{ + Frag *f, *ef; + Mem *m; + + /* look for local frag */ + f = &p->local[0]; + ef = &p->local[NLocalFrag]; + for(;f<ef; f++) { + if(f->state == FragLocalFree) { + f->state = FragLocalAlloc; + goto Found; + } + } + lock(&freelist.lk); + f = freelist.frag; + if(f != nil) + freelist.frag = f->next; + else + freelist.nfrag++; + unlock(&freelist.lk); + + if(f == nil) { + f = vtbrk(sizeof(Frag)); + f->state = FragGlobal; + } + +Found: + f->next = next; + f->p = p; + + if(n == 0){ + f->mem = 0; + f->rp = 0; + f->wp = 0; + return f; + } + + if(pos == PEnd && next == nil) + pos = PMiddle; + m = memalloc(n, pos); + f->mem = m; + f->rp = m->rp; + f->wp = m->wp; + return f; +} + +Packet* +packetforeign(uchar *buf, int n, void (*free)(void *a), void *a) +{ + Packet *p; + Frag *f; + + p = packetalloc(); + p->pc = getcallerpc(&buf); + f = fragalloc(p, 0, 0, nil); + f->free = free; + f->a = a; + f->next = nil; + f->rp = buf; + f->wp = buf+n; + + p->first = f; + p->last = f; + p->size = n; + NOTFREE(p); + return p; +} + +static Frag * +fragdup(Packet *p, Frag *f) +{ + Frag *ff; + Mem *m; + + m = f->mem; + + /* + * m->rp && m->wp can be out of date when ref == 1 + * also, potentially reclaims space from previous frags + */ + if(m && m->ref == 1) { + m->rp = f->rp; + m->wp = f->wp; + } + + ff = fragalloc(p, 0, 0, nil); + ff->mem = f->mem; + ff->rp = f->rp; + ff->wp = f->wp; + ff->next = f->next; + + /* + * We can't duplicate these -- there's no dup function. + */ + assert(f->free==nil && f->a==nil); + + if(m){ + lock(&m->lk); + m->ref++; + unlock(&m->lk); + } + + + return ff; +} + + +static void +fragfree(Frag *f) +{ + if(f->mem == nil){ + if(f->free) + (*f->free)(f->a); + }else{ + memfree(f->mem); + f->mem = 0; + } + + if(f->state == FragLocalAlloc) { + f->state = FragLocalFree; + return; + } + + lock(&freelist.lk); + f->next = freelist.frag; + freelist.frag = f; + unlock(&freelist.lk); +} + +static Mem * +memalloc(int n, int pos) +{ + Mem *m; + int nn; + + if(n < 0 || n > MaxFragSize) { + werrstr(EPacketSize); + return nil; + } + if(n <= SmallMemSize) { + lock(&freelist.lk); + m = freelist.smallmem; + if(m != nil) + freelist.smallmem = m->next; + else + freelist.nsmallmem++; + unlock(&freelist.lk); + nn = SmallMemSize; + } else { + lock(&freelist.lk); + m = freelist.bigmem; + if(m != nil) + freelist.bigmem = m->next; + else + freelist.nbigmem++; + unlock(&freelist.lk); + nn = BigMemSize; + } + + if(m == nil) { + m = vtbrk(sizeof(Mem)); + m->bp = vtbrk(nn); + m->ep = m->bp + nn; + } + assert(m->ref == 0); + m->ref = 1; + + switch(pos) { + default: + assert(0); + case PFront: + m->rp = m->bp; + break; + case PMiddle: + /* leave a little bit at end */ + m->rp = m->ep - n - 32; + break; + case PEnd: + m->rp = m->ep - n; + break; + } + /* check we did not blow it */ + if(m->rp < m->bp) + m->rp = m->bp; + m->wp = m->rp + n; + assert(m->rp >= m->bp && m->wp <= m->ep); + return m; +} + +static void +memfree(Mem *m) +{ + lock(&m->lk); + m->ref--; + if(m->ref > 0) { + unlock(&m->lk); + return; + } + unlock(&m->lk); + assert(m->ref == 0); + +/* memset(m->bp, 0xEF, m->ep-m->bp); */ + switch(m->ep - m->bp) { + default: + assert(0); + case SmallMemSize: + lock(&freelist.lk); + m->next = freelist.smallmem; + freelist.smallmem = m; + unlock(&freelist.lk); + break; + case BigMemSize: + lock(&freelist.lk); + m->next = freelist.bigmem; + freelist.bigmem = m; + unlock(&freelist.lk); + break; + } +} + +static int +memhead(Mem *m, uchar *rp, int n) +{ + fprint(2, "memhead called\n"); + abort(); + lock(&m->lk); + if(m->rp != rp) { + unlock(&m->lk); + return -1; + } + m->rp -= n; + unlock(&m->lk); + return 0; +} + +static int +memtail(Mem *m, uchar *wp, int n) +{ + fprint(2, "memtail called\n"); + abort(); + lock(&m->lk); + if(m->wp != wp) { + unlock(&m->lk); + return -1; + } + m->wp += n; + unlock(&m->lk); + return 0; +} + +#ifdef NOTDEF +static void +checkpacket(Packet *p) +{ + int s, as; + Frag *f; + Frag *ff; + + s = 0; + as = 0; + ff=p->first; + for(f=p->first; f; ff=f,f=f->next){ + assert(f->p == p); + s += FRAGSIZE(f); + as += FRAGASIZE(f); + } + assert(s == p->size); + assert(as == p->asize); + if(p->first) + assert(ff==p->last); +} +#endif diff --git a/sys/src/libventi/parsescore.c b/sys/src/libventi/parsescore.c new file mode 100755 index 000000000..bf4a6125b --- /dev/null +++ b/sys/src/libventi/parsescore.c @@ -0,0 +1,43 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +int +vtparsescore(char *s, char **prefix, uchar score[VtScoreSize]) +{ + int i, c; + char *buf, *colon; + + if((colon = strchr(s, ':')) != nil) + buf = colon+1; + else + buf = s; + + if(strlen(buf) != 2*VtScoreSize) + return -1; + + memset(score, 0, VtScoreSize); + for(i=0; i<2*VtScoreSize; i++){ + if(buf[i] >= '0' && buf[i] <= '9') + c = buf[i] - '0'; + else if(buf[i] >= 'a' && buf[i] <= 'z') + c = buf[i] - 'a' + 10; + else if(buf[i] >= 'A' && buf[i] <= 'Z') + c = buf[i] - 'A' + 10; + else + return -1; + + if((i & 1) == 0) + c <<= 4; + score[i>>1] |= c; + } + if(colon){ + *colon = 0; + if(prefix) + *prefix = s; + }else{ + if(prefix) + *prefix = nil; + } + return 0; +} diff --git a/sys/src/libventi/queue.c b/sys/src/libventi/queue.c new file mode 100755 index 000000000..bba630324 --- /dev/null +++ b/sys/src/libventi/queue.c @@ -0,0 +1,136 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> +#include "queue.h" + +typedef struct Qel Qel; +struct Qel +{ + Qel *next; + void *p; +}; + +struct Queue +{ + int ref; + int hungup; + QLock lk; + Rendez r; + Qel *head; + Qel *tail; +}; + +Queue* +_vtqalloc(void) +{ + Queue *q; + + q = vtmallocz(sizeof(Queue)); + q->r.l = &q->lk; + q->ref = 1; + return q; +} + +Queue* +_vtqincref(Queue *q) +{ + qlock(&q->lk); + q->ref++; + qunlock(&q->lk); + return q; +} + +void +_vtqdecref(Queue *q) +{ + Qel *e; + + qlock(&q->lk); + if(--q->ref > 0){ + qunlock(&q->lk); + return; + } + assert(q->ref == 0); + qunlock(&q->lk); + + /* Leaks the pointers e->p! */ + while(q->head){ + e = q->head; + q->head = e->next; + free(e); + } + free(q); +} + +int +_vtqsend(Queue *q, void *p) +{ + Qel *e; + + e = vtmalloc(sizeof(Qel)); + qlock(&q->lk); + if(q->hungup){ + werrstr("hungup queue"); + qunlock(&q->lk); + return -1; + } + e->p = p; + e->next = nil; + if(q->head == nil) + q->head = e; + else + q->tail->next = e; + q->tail = e; + rwakeup(&q->r); + qunlock(&q->lk); + return 0; +} + +void* +_vtqrecv(Queue *q) +{ + void *p; + Qel *e; + + qlock(&q->lk); + while(q->head == nil && !q->hungup) + rsleep(&q->r); + if(q->hungup){ + qunlock(&q->lk); + return nil; + } + e = q->head; + q->head = e->next; + qunlock(&q->lk); + p = e->p; + vtfree(e); + return p; +} + +void* +_vtnbqrecv(Queue *q) +{ + void *p; + Qel *e; + + qlock(&q->lk); + if(q->head == nil){ + qunlock(&q->lk); + return nil; + } + e = q->head; + q->head = e->next; + qunlock(&q->lk); + p = e->p; + vtfree(e); + return p; +} + +void +_vtqhangup(Queue *q) +{ + qlock(&q->lk); + q->hungup = 1; + rwakeupall(&q->r); + qunlock(&q->lk); +} diff --git a/sys/src/libventi/queue.h b/sys/src/libventi/queue.h new file mode 100755 index 000000000..f62725b1c --- /dev/null +++ b/sys/src/libventi/queue.h @@ -0,0 +1,9 @@ +typedef struct Queue Queue; +#pragma incomplete Queue +Queue *_vtqalloc(void); +int _vtqsend(Queue*, void*); +void *_vtqrecv(Queue*); +void _vtqhangup(Queue*); +void *_vtnbqrecv(Queue*); +void _vtqdecref(Queue*); +Queue *_vtqincref(Queue*); diff --git a/sys/src/libventi/root.c b/sys/src/libventi/root.c new file mode 100755 index 000000000..5b4ccac6e --- /dev/null +++ b/sys/src/libventi/root.c @@ -0,0 +1,67 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> +#include "cvt.h" + +static int +checksize(int n) +{ + if(n < 256 || n > VtMaxLumpSize) { + werrstr("bad block size"); + return -1; + } + return 0; +} + +void +vtrootpack(VtRoot *r, uchar *p) +{ + uchar *op = p; + + U16PUT(p, VtRootVersion); + p += 2; + memmove(p, r->name, sizeof(r->name)); + p += sizeof(r->name); + memmove(p, r->type, sizeof(r->type)); + p += sizeof(r->type); + memmove(p, r->score, VtScoreSize); + p += VtScoreSize; + U16PUT(p, r->blocksize); + p += 2; + memmove(p, r->prev, VtScoreSize); + p += VtScoreSize; + + assert(p-op == VtRootSize); +} + +int +vtrootunpack(VtRoot *r, uchar *p) +{ + uchar *op = p; + uint vers; + memset(r, 0, sizeof(*r)); + + vers = U16GET(p); + if(vers != VtRootVersion) { + werrstr("unknown root version"); + return -1; + } + p += 2; + memmove(r->name, p, sizeof(r->name)); + r->name[sizeof(r->name)-1] = 0; + p += sizeof(r->name); + memmove(r->type, p, sizeof(r->type)); + r->type[sizeof(r->type)-1] = 0; + p += sizeof(r->type); + memmove(r->score, p, VtScoreSize); + p += VtScoreSize; + r->blocksize = U16GET(p); + if(checksize(r->blocksize) < 0) + return -1; + p += 2; + memmove(r->prev, p, VtScoreSize); + p += VtScoreSize; + + assert(p-op == VtRootSize); + return 0; +} diff --git a/sys/src/libventi/rpc.acid b/sys/src/libventi/rpc.acid new file mode 100755 index 000000000..68f8f7834 --- /dev/null +++ b/sys/src/libventi/rpc.acid @@ -0,0 +1,710 @@ +sizeof_1_ = 8; +aggr _1_ +{ + 'U' 0 lo; + 'U' 4 hi; +}; + +defn +_1_(addr) { + complex _1_ addr; + print(" lo ", addr.lo, "\n"); + print(" hi ", addr.hi, "\n"); +}; + +sizeofFPdbleword = 8; +aggr FPdbleword +{ + 'F' 0 x; + { + 'U' 0 lo; + 'U' 4 hi; + }; +}; + +defn +FPdbleword(addr) { + complex FPdbleword addr; + print(" x ", addr.x, "\n"); + print("_1_ {\n"); + _1_(addr+0); + print("}\n"); +}; + +UTFmax = 3; +Runesync = 128; +Runeself = 128; +Runeerror = 65533; +sizeofFmt = 48; +aggr Fmt +{ + 'b' 0 runes; + 'X' 4 start; + 'X' 8 to; + 'X' 12 stop; + 'X' 16 flush; + 'X' 20 farg; + 'D' 24 nfmt; + 'X' 28 args; + 'D' 32 r; + 'D' 36 width; + 'D' 40 prec; + 'U' 44 flags; +}; + +defn +Fmt(addr) { + complex Fmt addr; + print(" runes ", addr.runes, "\n"); + print(" start ", addr.start\X, "\n"); + print(" to ", addr.to\X, "\n"); + print(" stop ", addr.stop\X, "\n"); + print(" flush ", addr.flush\X, "\n"); + print(" farg ", addr.farg\X, "\n"); + print(" nfmt ", addr.nfmt, "\n"); + print(" args ", addr.args\X, "\n"); + print(" r ", addr.r, "\n"); + print(" width ", addr.width, "\n"); + print(" prec ", addr.prec, "\n"); + print(" flags ", addr.flags, "\n"); +}; + +FmtWidth = 1; +FmtLeft = 2; +FmtPrec = 4; +FmtSharp = 8; +FmtSpace = 16; +FmtSign = 32; +FmtZero = 64; +FmtUnsigned = 128; +FmtShort = 256; +FmtLong = 512; +FmtVLong = 1024; +FmtComma = 2048; +FmtByte = 4096; +FmtFlag = 8192; +sizeofTm = 40; +aggr Tm +{ + 'D' 0 sec; + 'D' 4 min; + 'D' 8 hour; + 'D' 12 mday; + 'D' 16 mon; + 'D' 20 year; + 'D' 24 wday; + 'D' 28 yday; + 'a' 32 zone; + 'D' 36 tzoff; +}; + +defn +Tm(addr) { + complex Tm addr; + print(" sec ", addr.sec, "\n"); + print(" min ", addr.min, "\n"); + print(" hour ", addr.hour, "\n"); + print(" mday ", addr.mday, "\n"); + print(" mon ", addr.mon, "\n"); + print(" year ", addr.year, "\n"); + print(" wday ", addr.wday, "\n"); + print(" yday ", addr.yday, "\n"); + print(" zone ", addr.zone, "\n"); + print(" tzoff ", addr.tzoff, "\n"); +}; + +PNPROC = 1; +PNGROUP = 2; +Profoff = 0; +Profuser = 1; +Profkernel = 2; +Proftime = 3; +Profsample = 4; +sizeofLock = 4; +aggr Lock +{ + 'D' 0 val; +}; + +defn +Lock(addr) { + complex Lock addr; + print(" val ", addr.val, "\n"); +}; + +sizeofQLp = 12; +aggr QLp +{ + 'D' 0 inuse; + 'A' QLp 4 next; + 'C' 8 state; +}; + +defn +QLp(addr) { + complex QLp addr; + print(" inuse ", addr.inuse, "\n"); + print(" next ", addr.next\X, "\n"); + print(" state ", addr.state, "\n"); +}; + +sizeofQLock = 16; +aggr QLock +{ + Lock 0 lock; + 'D' 4 locked; + 'A' QLp 8 $head; + 'A' QLp 12 $tail; +}; + +defn +QLock(addr) { + complex QLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" locked ", addr.locked, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofRWLock = 20; +aggr RWLock +{ + Lock 0 lock; + 'D' 4 readers; + 'D' 8 writer; + 'A' QLp 12 $head; + 'A' QLp 16 $tail; +}; + +defn +RWLock(addr) { + complex RWLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" readers ", addr.readers, "\n"); + print(" writer ", addr.writer, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofRendez = 12; +aggr Rendez +{ + 'A' QLock 0 l; + 'A' QLp 4 $head; + 'A' QLp 8 $tail; +}; + +defn +Rendez(addr) { + complex Rendez addr; + print(" l ", addr.l\X, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofNetConnInfo = 36; +aggr NetConnInfo +{ + 'X' 0 dir; + 'X' 4 root; + 'X' 8 spec; + 'X' 12 lsys; + 'X' 16 lserv; + 'X' 20 rsys; + 'X' 24 rserv; + 'X' 28 laddr; + 'X' 32 raddr; +}; + +defn +NetConnInfo(addr) { + complex NetConnInfo addr; + print(" dir ", addr.dir\X, "\n"); + print(" root ", addr.root\X, "\n"); + print(" spec ", addr.spec\X, "\n"); + print(" lsys ", addr.lsys\X, "\n"); + print(" lserv ", addr.lserv\X, "\n"); + print(" rsys ", addr.rsys\X, "\n"); + print(" rserv ", addr.rserv\X, "\n"); + print(" laddr ", addr.laddr\X, "\n"); + print(" raddr ", addr.raddr\X, "\n"); +}; + +RFNAMEG = 1; +RFENVG = 2; +RFFDG = 4; +RFNOTEG = 8; +RFPROC = 16; +RFMEM = 32; +RFNOWAIT = 64; +RFCNAMEG = 1024; +RFCENVG = 2048; +RFCFDG = 4096; +RFREND = 8192; +RFNOMNT = 16384; +sizeofQid = 16; +aggr Qid +{ + 'W' 0 path; + 'U' 8 vers; + 'b' 12 type; +}; + +defn +Qid(addr) { + complex Qid addr; + print(" path ", addr.path, "\n"); + print(" vers ", addr.vers, "\n"); + print(" type ", addr.type, "\n"); +}; + +sizeofDir = 60; +aggr Dir +{ + 'u' 0 type; + 'U' 4 dev; + Qid 8 qid; + 'U' 24 mode; + 'U' 28 atime; + 'U' 32 mtime; + 'V' 36 length; + 'X' 44 name; + 'X' 48 uid; + 'X' 52 gid; + 'X' 56 muid; +}; + +defn +Dir(addr) { + complex Dir addr; + print(" type ", addr.type, "\n"); + print(" dev ", addr.dev, "\n"); + print("Qid qid {\n"); + Qid(addr.qid); + print("}\n"); + print(" mode ", addr.mode, "\n"); + print(" atime ", addr.atime, "\n"); + print(" mtime ", addr.mtime, "\n"); + print(" length ", addr.length, "\n"); + print(" name ", addr.name\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" gid ", addr.gid\X, "\n"); + print(" muid ", addr.muid\X, "\n"); +}; + +sizeofWaitmsg = 20; +aggr Waitmsg +{ + 'D' 0 pid; + 'a' 4 time; + 'X' 16 msg; +}; + +defn +Waitmsg(addr) { + complex Waitmsg addr; + print(" pid ", addr.pid, "\n"); + print(" time ", addr.time, "\n"); + print(" msg ", addr.msg\X, "\n"); +}; + +sizeofIOchunk = 8; +aggr IOchunk +{ + 'X' 0 addr; + 'U' 4 len; +}; + +defn +IOchunk(addr) { + complex IOchunk addr; + print(" addr ", addr.addr\X, "\n"); + print(" len ", addr.len, "\n"); +}; + +MaxFragSize = 9216; +sizeofVtLog = 40; +aggr VtLog +{ + 'A' VtLog 0 next; + 'X' 4 name; + 'X' 8 chunk; + 'U' 12 nchunk; + 'X' 16 w; + QLock 20 lk; + 'D' 36 ref; +}; + +defn +VtLog(addr) { + complex VtLog addr; + print(" next ", addr.next\X, "\n"); + print(" name ", addr.name\X, "\n"); + print(" chunk ", addr.chunk\X, "\n"); + print(" nchunk ", addr.nchunk, "\n"); + print(" w ", addr.w\X, "\n"); + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print(" ref ", addr.ref, "\n"); +}; + +sizeofVtLogChunk = 12; +aggr VtLogChunk +{ + 'X' 0 p; + 'X' 4 ep; + 'X' 8 wp; +}; + +defn +VtLogChunk(addr) { + complex VtLogChunk addr; + print(" p ", addr.p\X, "\n"); + print(" ep ", addr.ep\X, "\n"); + print(" wp ", addr.wp\X, "\n"); +}; + +VtScoreSize = 20; +VtMaxStringSize = 1024; +VtMaxLumpSize = 57344; +VtPointerDepth = 7; +VtDataType = 0; +VtDirType = 8; +VtRootType = 16; +VtMaxType = 17; +VtCorruptType = 255; +VtTypeDepthMask = 7; +VtTypeBaseMask = -8; +VtEntryActive = 1; +_VtEntryDir = 2; +_VtEntryDepthShift = 2; +_VtEntryDepthMask = 28; +VtEntryLocal = 32; +VtEntrySize = 40; +sizeofVtEntry = 40; +aggr VtEntry +{ + 'U' 0 gen; + 'u' 4 psize; + 'u' 6 dsize; + 'b' 8 type; + 'b' 9 flags; + 'W' 12 size; + 'a' 20 score; +}; + +defn +VtEntry(addr) { + complex VtEntry addr; + print(" gen ", addr.gen, "\n"); + print(" psize ", addr.psize, "\n"); + print(" dsize ", addr.dsize, "\n"); + print(" type ", addr.type, "\n"); + print(" flags ", addr.flags, "\n"); + print(" size ", addr.size, "\n"); + print(" score ", addr.score, "\n"); +}; + +sizeofVtRoot = 300; +aggr VtRoot +{ + 'a' 0 name; + 'a' 128 type; + 'a' 256 score; + 'u' 276 blocksize; + 'a' 278 prev; +}; + +defn +VtRoot(addr) { + complex VtRoot addr; + print(" name ", addr.name, "\n"); + print(" type ", addr.type, "\n"); + print(" score ", addr.score, "\n"); + print(" blocksize ", addr.blocksize, "\n"); + print(" prev ", addr.prev, "\n"); +}; + +VtRootSize = 300; +VtRootVersion = 2; +VtCryptoStrengthNone = 0; +VtCryptoStrengthAuth = 1; +VtCryptoStrengthWeak = 2; +VtCryptoStrengthStrong = 3; +VtCryptoNone = 0; +VtCryptoSSL3 = 1; +VtCryptoTLS1 = 2; +VtCryptoMax = 3; +VtCodecNone = 0; +VtCodecDeflate = 1; +VtCodecThwack = 2; +VtCodecMax = 3; +VtRerror = 1; +VtTping = 2; +VtRping = 3; +VtThello = 4; +VtRhello = 5; +VtTgoodbye = 6; +VtRgoodbye = 7; +VtTauth0 = 8; +VtRauth0 = 9; +VtTauth1 = 10; +VtRauth1 = 11; +VtTread = 12; +VtRread = 13; +VtTwrite = 14; +VtRwrite = 15; +VtTsync = 16; +VtRsync = 17; +VtTmax = 18; +sizeofVtFcall = 80; +aggr VtFcall +{ + 'b' 0 msgtype; + 'b' 1 tag; + 'X' 4 error; + 'X' 8 version; + 'X' 12 uid; + 'b' 16 strength; + 'X' 20 crypto; + 'U' 24 ncrypto; + 'X' 28 codec; + 'U' 32 ncodec; + 'X' 36 sid; + 'b' 40 rcrypto; + 'b' 41 rcodec; + 'X' 44 auth; + 'U' 48 nauth; + 'a' 52 score; + 'b' 72 blocktype; + 'u' 74 count; + 'X' 76 data; +}; + +defn +VtFcall(addr) { + complex VtFcall addr; + print(" msgtype ", addr.msgtype, "\n"); + print(" tag ", addr.tag, "\n"); + print(" error ", addr.error\X, "\n"); + print(" version ", addr.version\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" strength ", addr.strength, "\n"); + print(" crypto ", addr.crypto\X, "\n"); + print(" ncrypto ", addr.ncrypto, "\n"); + print(" codec ", addr.codec\X, "\n"); + print(" ncodec ", addr.ncodec, "\n"); + print(" sid ", addr.sid\X, "\n"); + print(" rcrypto ", addr.rcrypto, "\n"); + print(" rcodec ", addr.rcodec, "\n"); + print(" auth ", addr.auth\X, "\n"); + print(" nauth ", addr.nauth, "\n"); + print(" score ", addr.score, "\n"); + print(" blocktype ", addr.blocktype, "\n"); + print(" count ", addr.count, "\n"); + print(" data ", addr.data\X, "\n"); +}; + +VtStateAlloc = 0; +VtStateConnected = 1; +VtStateClosed = 2; +sizeofVtConn = 1404; +aggr VtConn +{ + QLock 0 lk; + QLock 16 inlk; + QLock 32 outlk; + 'D' 48 debug; + 'D' 52 infd; + 'D' 56 outfd; + 'D' 60 muxer; + 'X' 64 writeq; + 'X' 68 readq; + 'D' 72 state; + 'a' 76 wait; + 'U' 1100 ntag; + 'U' 1104 nsleep; + 'X' 1108 part; + Rendez 1112 tagrend; + Rendez 1124 rpcfork; + 'X' 1136 version; + 'X' 1140 uid; + 'X' 1144 sid; + 'a' 1148 addr; +}; + +defn +VtConn(addr) { + complex VtConn addr; + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print("QLock inlk {\n"); + QLock(addr.inlk); + print("}\n"); + print("QLock outlk {\n"); + QLock(addr.outlk); + print("}\n"); + print(" debug ", addr.debug, "\n"); + print(" infd ", addr.infd, "\n"); + print(" outfd ", addr.outfd, "\n"); + print(" muxer ", addr.muxer, "\n"); + print(" writeq ", addr.writeq\X, "\n"); + print(" readq ", addr.readq\X, "\n"); + print(" state ", addr.state, "\n"); + print(" wait ", addr.wait, "\n"); + print(" ntag ", addr.ntag, "\n"); + print(" nsleep ", addr.nsleep, "\n"); + print(" part ", addr.part\X, "\n"); + print("Rendez tagrend {\n"); + Rendez(addr.tagrend); + print("}\n"); + print("Rendez rpcfork {\n"); + Rendez(addr.rpcfork); + print("}\n"); + print(" version ", addr.version\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" sid ", addr.sid\X, "\n"); + print(" addr ", addr.addr, "\n"); +}; + +sizeofVtReq = 168; +aggr VtReq +{ + VtFcall 0 tx; + VtFcall 80 rx; + 'X' 160 srv; + 'X' 164 sc; +}; + +defn +VtReq(addr) { + complex VtReq addr; + print("VtFcall tx {\n"); + VtFcall(addr.tx); + print("}\n"); + print("VtFcall rx {\n"); + VtFcall(addr.rx); + print("}\n"); + print(" srv ", addr.srv\X, "\n"); + print(" sc ", addr.sc\X, "\n"); +}; + +NilBlock = -1; +sizeofVtBlock = 84; +aggr VtBlock +{ + 'X' 0 c; + QLock 4 lk; + 'X' 20 data; + 'a' 24 score; + 'b' 44 type; + 'D' 48 nlock; + 'D' 52 iostate; + 'D' 56 ref; + 'U' 60 heap; + 'A' VtBlock 64 next; + 'A' VtBlock 68 prev; + 'U' 72 used; + 'U' 76 used2; + 'U' 80 addr; +}; + +defn +VtBlock(addr) { + complex VtBlock addr; + print(" c ", addr.c\X, "\n"); + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print(" data ", addr.data\X, "\n"); + print(" score ", addr.score, "\n"); + print(" type ", addr.type, "\n"); + print(" nlock ", addr.nlock, "\n"); + print(" iostate ", addr.iostate, "\n"); + print(" ref ", addr.ref, "\n"); + print(" heap ", addr.heap, "\n"); + print(" next ", addr.next\X, "\n"); + print(" prev ", addr.prev\X, "\n"); + print(" used ", addr.used, "\n"); + print(" used2 ", addr.used2, "\n"); + print(" addr ", addr.addr, "\n"); +}; + +sizeofVtFile = 84; +aggr VtFile +{ + QLock 0 lk; + 'D' 16 ref; + 'D' 20 $local; + 'A' VtBlock 24 b; + 'a' 28 score; + 'X' 48 c; + 'D' 52 mode; + 'U' 56 gen; + 'D' 60 dsize; + 'D' 64 psize; + 'D' 68 dir; + 'A' VtFile 72 parent; + 'D' 76 epb; + 'U' 80 offset; +}; + +defn +VtFile(addr) { + complex VtFile addr; + print("QLock lk {\n"); + QLock(addr.lk); + print("}\n"); + print(" ref ", addr.ref, "\n"); + print(" $local ", addr.$local, "\n"); + print(" b ", addr.b\X, "\n"); + print(" score ", addr.score, "\n"); + print(" c ", addr.c\X, "\n"); + print(" mode ", addr.mode, "\n"); + print(" gen ", addr.gen, "\n"); + print(" dsize ", addr.dsize, "\n"); + print(" psize ", addr.psize, "\n"); + print(" dir ", addr.dir, "\n"); + print(" parent ", addr.parent\X, "\n"); + print(" epb ", addr.epb, "\n"); + print(" offset ", addr.offset, "\n"); +}; + +VtOREAD = 0; +VtOWRITE = 1; +VtORDWR = 2; +sizeofRwait = 24; +aggr Rwait +{ + Rendez 0 r; + 'X' 12 p; + 'D' 16 done; + 'D' 20 sleeping; +}; + +defn +Rwait(addr) { + complex Rwait addr; + print("Rendez r {\n"); + Rendez(addr.r); + print("}\n"); + print(" p ", addr.p\X, "\n"); + print(" done ", addr.done, "\n"); + print(" sleeping ", addr.sleeping, "\n"); +}; + +complex VtConn vtrpc:z; +complex Rwait vtrpc:r; +complex Rwait vtrpc:rr; +complex VtConn gettag:z; +complex Rwait gettag:r; +complex VtConn puttag:z; +complex Rwait puttag:r; +complex VtConn muxrpc:z; +complex Rwait muxrpc:r; diff --git a/sys/src/libventi/rpc.c b/sys/src/libventi/rpc.c new file mode 100755 index 000000000..5a820a995 --- /dev/null +++ b/sys/src/libventi/rpc.c @@ -0,0 +1,173 @@ +/* + * Multiplexed Venti client. It would be nice if we + * could turn this into a generic library routine rather + * than keep it Venti specific. A user-level 9P client + * could use something like this too. + * + * (Actually it does - this should be replaced with libmux, + * which should be renamed librpcmux.) + * + * This is a little more complicated than it might be + * because we want it to work well within and without libthread. + * + * The mux code is inspired by tra's, which is inspired by the Plan 9 kernel. + */ + +#include <u.h> +#include <libc.h> +#include <venti.h> + +typedef struct Rwait Rwait; +struct Rwait +{ + Rendez r; + Packet *p; + int done; + int sleeping; +}; + +static int gettag(VtConn*, Rwait*); +static void puttag(VtConn*, Rwait*, int); +static void muxrpc(VtConn*, Packet*); + +Packet* +_vtrpc(VtConn *z, Packet *p, VtFcall *tx) +{ + int i; + uchar tag, buf[2], *top; + Rwait *r, *rr; + + /* must malloc because stack could be private */ + r = vtmallocz(sizeof(Rwait)); + + qlock(&z->lk); + r->r.l = &z->lk; + tag = gettag(z, r); + if(tx){ + /* vtfcallrpc can't print packet because it doesn't have tag */ + tx->tag = tag; + if(chattyventi) + fprint(2, "%s -> %F\n", argv0, tx); + } + + /* slam tag into packet */ + top = packetpeek(p, buf, 0, 2); + if(top == nil){ + packetfree(p); + return nil; + } + if(top == buf){ + werrstr("first two bytes must be in same packet fragment"); + packetfree(p); + vtfree(r); + return nil; + } + top[1] = tag; + qunlock(&z->lk); + if(vtsend(z, p) < 0){ + vtfree(r); + return nil; + } + + qlock(&z->lk); + /* wait for the muxer to give us our packet */ + r->sleeping = 1; + z->nsleep++; + while(z->muxer && !r->done) + rsleep(&r->r); + z->nsleep--; + r->sleeping = 0; + + /* if not done, there's no muxer: start muxing */ + if(!r->done){ + if(z->muxer) + abort(); + z->muxer = 1; + while(!r->done){ + qunlock(&z->lk); + if((p = vtrecv(z)) == nil){ + werrstr("unexpected eof on venti connection"); + z->muxer = 0; + vtfree(r); + return nil; + } + qlock(&z->lk); + muxrpc(z, p); + } + z->muxer = 0; + /* if there is anyone else sleeping, wake first unfinished to mux */ + if(z->nsleep) + for(i=0; i<256; i++){ + rr = z->wait[i]; + if(rr && rr->sleeping && !rr->done){ + rwakeup(&rr->r); + break; + } + } + } + + p = r->p; + puttag(z, r, tag); + vtfree(r); + qunlock(&z->lk); + return p; +} + +Packet* +vtrpc(VtConn *z, Packet *p) +{ + return _vtrpc(z, p, nil); +} + +static int +gettag(VtConn *z, Rwait *r) +{ + int i; + +Again: + while(z->ntag == 256) + rsleep(&z->tagrend); + for(i=0; i<256; i++) + if(z->wait[i] == 0){ + z->ntag++; + z->wait[i] = r; + return i; + } + fprint(2, "libventi: ntag botch\n"); + goto Again; +} + +static void +puttag(VtConn *z, Rwait *r, int tag) +{ + assert(z->wait[tag] == r); + z->wait[tag] = nil; + z->ntag--; + rwakeup(&z->tagrend); +} + +static void +muxrpc(VtConn *z, Packet *p) +{ + uchar tag, buf[2], *top; + Rwait *r; + + if((top = packetpeek(p, buf, 0, 2)) == nil){ + fprint(2, "libventi: short packet in vtrpc\n"); + packetfree(p); + return; + } + + tag = top[1]; + if((r = z->wait[tag]) == nil){ + fprint(2, "libventi: unexpected packet tag %d in vtrpc\n", tag); +abort(); + packetfree(p); + return; + } + + r->p = p; + r->done = 1; + rwakeup(&r->r); +} + diff --git a/sys/src/libventi/scorefmt.c b/sys/src/libventi/scorefmt.c new file mode 100755 index 000000000..496f85b7b --- /dev/null +++ b/sys/src/libventi/scorefmt.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +int +vtscorefmt(Fmt *f) +{ + uchar *v; + int i; + + v = va_arg(f->args, uchar*); + if(v == nil) + fmtprint(f, "*"); + else + for(i = 0; i < VtScoreSize; i++) + fmtprint(f, "%2.2ux", v[i]); + return 0; +} diff --git a/sys/src/libventi/send.c b/sys/src/libventi/send.c new file mode 100755 index 000000000..2b88818da --- /dev/null +++ b/sys/src/libventi/send.c @@ -0,0 +1,251 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> +#include "queue.h" + +long ventisendbytes, ventisendpackets; +long ventirecvbytes, ventirecvpackets; + +static int +_vtsend(VtConn *z, Packet *p) +{ + IOchunk ioc; + int n, tot; + uchar buf[2]; + + if(z->state != VtStateConnected) { + werrstr("session not connected"); + return -1; + } + + /* add framing */ + n = packetsize(p); + if(n >= (1<<16)) { + werrstr("packet too large"); + packetfree(p); + return -1; + } + buf[0] = n>>8; + buf[1] = n; + packetprefix(p, buf, 2); + ventisendbytes += n+2; + ventisendpackets++; + + tot = 0; + for(;;){ + n = packetfragments(p, &ioc, 1, 0); + if(n == 0) + break; + if(write(z->outfd, ioc.addr, ioc.len) < ioc.len){ + vtlog(VtServerLog, "<font size=-1>%T %s:</font> sending packet %p: %r<br>\n", z->addr, p); + packetfree(p); + return -1; + } + packetconsume(p, nil, ioc.len); + tot += ioc.len; + } + vtlog(VtServerLog, "<font size=-1>%T %s:</font> sent packet %p (%d bytes)<br>\n", z->addr, p, tot); + packetfree(p); + return 1; +} + +static int +interrupted(void) +{ + char e[ERRMAX]; + + rerrstr(e, sizeof e); + return strstr(e, "interrupted") != nil; +} + + +static Packet* +_vtrecv(VtConn *z) +{ + uchar buf[10], *b; + int n; + Packet *p; + int size, len; + + if(z->state != VtStateConnected) { + werrstr("session not connected"); + return nil; + } + + p = z->part; + /* get enough for head size */ + size = packetsize(p); + while(size < 2) { + b = packettrailer(p, 2); + assert(b != nil); + if(0) fprint(2, "%d read hdr\n", getpid()); + n = read(z->infd, b, 2); + if(0) fprint(2, "%d got %d (%r)\n", getpid(), n); + if(n==0 || (n<0 && !interrupted())) + goto Err; + size += n; + packettrim(p, 0, size); + } + + if(packetconsume(p, buf, 2) < 0) + goto Err; + len = (buf[0] << 8) | buf[1]; + size -= 2; + + while(size < len) { + n = len - size; + if(n > MaxFragSize) + n = MaxFragSize; + b = packettrailer(p, n); + if(0) fprint(2, "%d read body %d\n", getpid(), n); + n = read(z->infd, b, n); + if(0) fprint(2, "%d got %d (%r)\n", getpid(), n); + if(n > 0) + size += n; + packettrim(p, 0, size); + if(n==0 || (n<0 && !interrupted())) + goto Err; + } + ventirecvbytes += len; + ventirecvpackets++; + p = packetsplit(p, len); + vtlog(VtServerLog, "<font size=-1>%T %s:</font> read packet %p len %d<br>\n", z->addr, p, len); + return p; +Err: + vtlog(VtServerLog, "<font size=-1>%T %s:</font> error reading packet: %r<br>\n", z->addr); + return nil; +} + +/* + * If you fork off two procs running vtrecvproc and vtsendproc, + * then vtrecv/vtsend (and thus vtrpc) will never block except on + * rendevouses, which is nice when it's running in one thread of many. + */ +void +vtrecvproc(void *v) +{ + Packet *p; + VtConn *z; + Queue *q; + + z = v; + q = _vtqalloc(); + + qlock(&z->lk); + z->readq = q; + qlock(&z->inlk); + rwakeup(&z->rpcfork); + qunlock(&z->lk); + + while((p = _vtrecv(z)) != nil) + if(_vtqsend(q, p) < 0){ + packetfree(p); + break; + } + qunlock(&z->inlk); + qlock(&z->lk); + _vtqhangup(q); + while((p = _vtnbqrecv(q)) != nil) + packetfree(p); + _vtqdecref(q); + z->readq = nil; + rwakeup(&z->rpcfork); + qunlock(&z->lk); + vthangup(z); +} + +void +vtsendproc(void *v) +{ + Queue *q; + Packet *p; + VtConn *z; + + z = v; + q = _vtqalloc(); + + qlock(&z->lk); + z->writeq = q; + qlock(&z->outlk); + rwakeup(&z->rpcfork); + qunlock(&z->lk); + + while((p = _vtqrecv(q)) != nil) + if(_vtsend(z, p) < 0) + break; + qunlock(&z->outlk); + qlock(&z->lk); + _vtqhangup(q); + while((p = _vtnbqrecv(q)) != nil) + packetfree(p); + _vtqdecref(q); + z->writeq = nil; + rwakeup(&z->rpcfork); + qunlock(&z->lk); + return; +} + +Packet* +vtrecv(VtConn *z) +{ + Packet *p; + Queue *q; + + qlock(&z->lk); + if(z->state != VtStateConnected){ + werrstr("not connected"); + qunlock(&z->lk); + return nil; + } + if(z->readq){ + q = _vtqincref(z->readq); + qunlock(&z->lk); + p = _vtqrecv(q); + _vtqdecref(q); + return p; + } + + qlock(&z->inlk); + qunlock(&z->lk); + p = _vtrecv(z); + qunlock(&z->inlk); + if(!p) + vthangup(z); + return p; +} + +int +vtsend(VtConn *z, Packet *p) +{ + Queue *q; + + qlock(&z->lk); + if(z->state != VtStateConnected){ + packetfree(p); + werrstr("not connected"); + qunlock(&z->lk); + return -1; + } + if(z->writeq){ + q = _vtqincref(z->writeq); + qunlock(&z->lk); + if(_vtqsend(q, p) < 0){ + _vtqdecref(q); + packetfree(p); + return -1; + } + _vtqdecref(q); + return 0; + } + + qlock(&z->outlk); + qunlock(&z->lk); + if(_vtsend(z, p) < 0){ + qunlock(&z->outlk); + vthangup(z); + return -1; + } + qunlock(&z->outlk); + return 0; +} + diff --git a/sys/src/libventi/server.c b/sys/src/libventi/server.c new file mode 100755 index 000000000..10b0665fd --- /dev/null +++ b/sys/src/libventi/server.c @@ -0,0 +1,215 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> +#include <thread.h> +#include "queue.h" + +enum +{ + STACK = 8192 +}; + +typedef struct VtSconn VtSconn; +struct VtSconn +{ + int ctl; + int ref; + QLock lk; + char dir[NETPATHLEN]; + VtSrv *srv; + VtConn *c; +}; + +struct VtSrv +{ + int afd; + int dead; + char adir[NETPATHLEN]; + Queue *q; /* Queue(VtReq*) */ +}; + +static void listenproc(void*); +static void connproc(void*); + +static void +scincref(VtSconn *sc) +{ + qlock(&sc->lk); + sc->ref++; + qunlock(&sc->lk); +} + +static void +scdecref(VtSconn *sc) +{ + qlock(&sc->lk); + if(--sc->ref > 0){ + qunlock(&sc->lk); + return; + } + if(sc->c) + vtfreeconn(sc->c); + vtfree(sc); +} + +VtSrv* +vtlisten(char *addr) +{ + VtSrv *s; + + s = vtmallocz(sizeof(VtSrv)); + s->afd = announce(addr, s->adir); + if(s->afd < 0){ + free(s); + return nil; + } + s->q = _vtqalloc(); + proccreate(listenproc, s, STACK); + return s; +} + +static void +listenproc(void *v) +{ + int ctl; + char dir[NETPATHLEN]; + VtSrv *srv; + VtSconn *sc; + + srv = v; + for(;;){ + ctl = listen(srv->adir, dir); + if(ctl < 0){ + srv->dead = 1; + break; + } + sc = vtmallocz(sizeof(VtSconn)); + sc->ref = 1; + sc->ctl = ctl; + sc->srv = srv; + strcpy(sc->dir, dir); + proccreate(connproc, sc, STACK); + } + + /* hangup */ +} + +static void +connproc(void *v) +{ + VtSconn *sc; + VtConn *c; + Packet *p; + VtReq *r; + int fd; +static int first=1; + +if(first && chattyventi){ + first=0; + fmtinstall('F', vtfcallfmt); +} + r = nil; + sc = v; + sc->c = nil; + if(0) fprint(2, "new call %s on %d\n", sc->dir, sc->ctl); + fd = accept(sc->ctl, sc->dir); + close(sc->ctl); + if(fd < 0){ + fprint(2, "accept %s: %r\n", sc->dir); + goto out; + } + + c = vtconn(fd, fd); + sc->c = c; + if(vtversion(c) < 0){ + fprint(2, "vtversion %s: %r\n", sc->dir); + goto out; + } + if(vtsrvhello(c) < 0){ + fprint(2, "vtsrvhello %s: %r\n", sc->dir); + goto out; + } + + if(0) fprint(2, "new proc %s\n", sc->dir); + proccreate(vtsendproc, c, STACK); + qlock(&c->lk); + while(!c->writeq) + rsleep(&c->rpcfork); + qunlock(&c->lk); + + while((p = vtrecv(c)) != nil){ + r = vtmallocz(sizeof(VtReq)); + if(vtfcallunpack(&r->tx, p) < 0){ + vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv bad packet %p: %r<br>\n", c->addr, p); + fprint(2, "bad packet on %s: %r\n", sc->dir); + packetfree(p); + continue; + } + vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv packet %p (%F)<br>\n", c->addr, p, &r->tx); + if(chattyventi) + fprint(2, "%s <- %F\n", argv0, &r->tx); + packetfree(p); + if(r->tx.msgtype == VtTgoodbye) + break; + r->rx.tag = r->tx.tag; + r->sc = sc; + scincref(sc); + if(_vtqsend(sc->srv->q, r) < 0){ + scdecref(sc); + fprint(2, "hungup queue\n"); + break; + } + r = nil; + } + + if(0) fprint(2, "eof on %s\n", sc->dir); + +out: + if(r){ + vtfcallclear(&r->tx); + vtfree(r); + } + if(0) fprint(2, "freed %s\n", sc->dir); + scdecref(sc); + return; +} + +VtReq* +vtgetreq(VtSrv *srv) +{ + VtReq *r; + + r = _vtqrecv(srv->q); + vtlog(VtServerLog, "<font size=-1>%T %s:</font> vtgetreq %F<br>\n", ((VtSconn*)r->sc)->c->addr, &r->tx); + return r; +} + +void +vtrespond(VtReq *r) +{ + Packet *p; + VtSconn *sc; + + sc = r->sc; + if(r->rx.tag != r->tx.tag) + abort(); + if(r->rx.msgtype != r->tx.msgtype+1 && r->rx.msgtype != VtRerror) + abort(); + if(chattyventi) + fprint(2, "%s -> %F\n", argv0, &r->rx); + if((p = vtfcallpack(&r->rx)) == nil){ + vtlog(VtServerLog, "%s: vtfcallpack %F: %r<br>\n", sc->c->addr, &r->rx); + fprint(2, "fcallpack on %s: %r\n", sc->dir); + packetfree(p); + vtfcallclear(&r->rx); + return; + } + vtlog(VtServerLog, "<font size=-1>%T %s:</font> send packet %p (%F)<br>\n", sc->c->addr, p, &r->rx); + if(vtsend(sc->c, p) < 0) + fprint(2, "vtsend %F: %r\n", &r->rx); + scdecref(sc); + vtfcallclear(&r->tx); + vtfcallclear(&r->rx); + vtfree(r); +} + diff --git a/sys/src/libventi/srvhello.c b/sys/src/libventi/srvhello.c new file mode 100755 index 000000000..ca34221e6 --- /dev/null +++ b/sys/src/libventi/srvhello.c @@ -0,0 +1,50 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +int +vtsrvhello(VtConn *z) +{ + VtFcall tx, rx; + Packet *p; + + if((p = vtrecv(z)) == nil) + return -1; + + if(vtfcallunpack(&tx, p) < 0){ + packetfree(p); + return -1; + } + packetfree(p); + + if(tx.msgtype != VtThello){ + vtfcallclear(&tx); + werrstr("bad packet type %d; want Thello %d", tx.msgtype, VtThello); + return -1; + } + if(tx.tag != 0){ + vtfcallclear(&tx); + werrstr("bad tag in hello"); + return -1; + } + if(strcmp(tx.version, z->version) != 0){ + vtfcallclear(&tx); + werrstr("bad version in hello"); + return -1; + } + vtfree(z->uid); + z->uid = tx.uid; + tx.uid = nil; + vtfcallclear(&tx); + + memset(&rx, 0, sizeof rx); + rx.msgtype = VtRhello; + rx.tag = tx.tag; + rx.sid = "anonymous"; + if((p = vtfcallpack(&rx)) == nil) + return -1; + if(vtsend(z, p) < 0) + return -1; + + return 0; +} diff --git a/sys/src/libventi/strdup.c b/sys/src/libventi/strdup.c new file mode 100755 index 000000000..e191c390c --- /dev/null +++ b/sys/src/libventi/strdup.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +char* +vtstrdup(char *s) +{ + int n; + char *ss; + + if(s == nil) + return nil; + n = strlen(s) + 1; + ss = vtmalloc(n); + memmove(ss, s, n); + return ss; +} + diff --git a/sys/src/libventi/string.c b/sys/src/libventi/string.c new file mode 100755 index 000000000..9763149a1 --- /dev/null +++ b/sys/src/libventi/string.c @@ -0,0 +1,50 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +int +vtputstring(Packet *p, char *s) +{ + uchar buf[2]; + int n; + + if(s == nil){ + werrstr("null string in packet"); + return -1; + } + n = strlen(s); + if(n > VtMaxStringSize){ + werrstr("string too long in packet"); + return -1; + } + buf[0] = n>>8; + buf[1] = n; + packetappend(p, buf, 2); + packetappend(p, (uchar*)s, n); + return 0; +} + +int +vtgetstring(Packet *p, char **ps) +{ + uchar buf[2]; + int n; + char *s; + + if(packetconsume(p, buf, 2) < 0) + return -1; + n = (buf[0]<<8) + buf[1]; + if(n > VtMaxStringSize) { + werrstr("string too long in packet"); + return -1; + } + s = vtmalloc(n+1); + if(packetconsume(p, (uchar*)s, n) < 0){ + vtfree(s); + return -1; + } + s[n] = 0; + *ps = s; + return 0; +} + diff --git a/sys/src/libventi/time.c b/sys/src/libventi/time.c new file mode 100755 index 000000000..2d8058f13 --- /dev/null +++ b/sys/src/libventi/time.c @@ -0,0 +1,25 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +int +vttimefmt(Fmt *fmt) +{ + vlong ns; + Tm tm; + + if(fmt->flags&FmtLong){ + ns = nsec(); + tm = *localtime(ns/1000000000); + return fmtprint(fmt, "%04d/%02d%02d %02d:%02d:%02d.%03d", + tm.year+1900, tm.mon+1, tm.mday, + tm.hour, tm.min, tm.sec, + (int)(ns%1000000000)/1000000); + }else{ + tm = *localtime(time(0)); + return fmtprint(fmt, "%04d/%02d%02d %02d:%02d:%02d", + tm.year+1900, tm.mon+1, tm.mday, + tm.hour, tm.min, tm.sec); + } +} + diff --git a/sys/src/libventi/version.c b/sys/src/libventi/version.c new file mode 100755 index 000000000..fd1e2389a --- /dev/null +++ b/sys/src/libventi/version.c @@ -0,0 +1,120 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +static char *okvers[] = { + "02", + nil, +}; + +/* +static char EBigString[] = "string too long"; +static char EBigPacket[] = "packet too long"; +static char ENullString[] = "missing string"; +*/ +static char EBadVersion[] = "bad format in version string"; + +static int +vtreadversion(VtConn *z, char *q, char *v, int nv) +{ + int n; + + for(;;){ + if(nv <= 1){ + werrstr("version too long"); + return -1; + } + n = read(z->infd, v, 1); + if(n <= 0){ + if(n == 0) + werrstr("unexpected eof"); + return -1; + } + if(*v == '\n'){ + *v = 0; + break; + } + if((uchar)*v < ' ' || (uchar)*v > 0x7f || (*q && *v != *q)){ + werrstr(EBadVersion); + return -1; + } + v++; + nv--; + if(*q) + q++; + } + return 0; +} + +int +vtversion(VtConn *z) +{ + char buf[VtMaxStringSize], *p, *ep, *prefix, *pp; + int i; + + qlock(&z->lk); + if(z->state != VtStateAlloc){ + werrstr("bad session state"); + qunlock(&z->lk); + return -1; + } + + qlock(&z->inlk); + qlock(&z->outlk); + + p = buf; + ep = buf + sizeof buf; + prefix = "venti-"; + p = seprint(p, ep, "%s", prefix); + p += strlen(p); + for(i=0; okvers[i]; i++) + p = seprint(p, ep, "%s%s", i ? ":" : "", okvers[i]); + p = seprint(p, ep, "-libventi\n"); + assert(p-buf < sizeof buf); + + if(write(z->outfd, buf, p-buf) != p-buf) + goto Err; + vtdebug(z, "version string out: %s", buf); + + if(vtreadversion(z, prefix, buf, sizeof buf) < 0) + goto Err; + vtdebug(z, "version string in: %s", buf); + + p = buf+strlen(prefix); + for(; *p; p=pp){ + if(*p == ':' || *p == '-') + p++; + pp = strpbrk(p, ":-"); + if(pp == nil) + pp = p+strlen(p); + for(i=0; okvers[i]; i++) + if(strlen(okvers[i]) == pp-p && memcmp(okvers[i], p, pp-p) == 0){ + *pp = 0; + z->version = vtstrdup(p); + goto Okay; + } + } + werrstr("unable to negotiate version"); + goto Err; + +Okay: + z->state = VtStateConnected; + qunlock(&z->inlk); + qunlock(&z->outlk); + qunlock(&z->lk); + return 0; + +Err: + werrstr("vtversion: %r"); + if(z->infd >= 0) + close(z->infd); + if(z->outfd >= 0 && z->outfd != z->infd) + close(z->outfd); + z->infd = -1; + z->outfd = -1; + z->state = VtStateClosed; + qunlock(&z->inlk); + qunlock(&z->outlk); + qunlock(&z->lk); + return -1; +} diff --git a/sys/src/libventi/zero.c b/sys/src/libventi/zero.c new file mode 100755 index 000000000..c40aea969 --- /dev/null +++ b/sys/src/libventi/zero.c @@ -0,0 +1,55 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +void +vtzeroextend(int type, uchar *buf, uint n, uint nn) +{ + uchar *p, *ep; + + switch(type&7) { + case 0: + memset(buf+n, 0, nn-n); + break; + default: + p = buf + (n/VtScoreSize)*VtScoreSize; + ep = buf + (nn/VtScoreSize)*VtScoreSize; + while(p < ep) { + memmove(p, vtzeroscore, VtScoreSize); + p += VtScoreSize; + } + memset(p, 0, buf+nn-p); + break; + } +} + +uint +vtzerotruncate(int type, uchar *buf, uint n) +{ + uchar *p; + + if(type == VtRootType){ + if(n < VtRootSize) + return n; + return VtRootSize; + } + + switch(type&7){ + case 0: + for(p = buf + n; p > buf; p--) { + if(p[-1] != 0) + break; + } + return p - buf; + default: + /* ignore slop at end of block */ + p = buf + (n/VtScoreSize)*VtScoreSize; + + while(p > buf) { + if(memcmp(p - VtScoreSize, vtzeroscore, VtScoreSize) != 0) + break; + p -= VtScoreSize; + } + return p - buf; + } +} diff --git a/sys/src/libventi/zeroscore.c b/sys/src/libventi/zeroscore.c new file mode 100755 index 000000000..6f22d72de --- /dev/null +++ b/sys/src/libventi/zeroscore.c @@ -0,0 +1,10 @@ +#include <u.h> +#include <libc.h> +#include <venti.h> + +/* score of a zero length block */ +uchar vtzeroscore[VtScoreSize] = { + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, + 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 +}; + |