diff options
author | aiju <aiju@phicode.de> | 2012-08-07 17:57:04 +0200 |
---|---|---|
committer | aiju <aiju@phicode.de> | 2012-08-07 17:57:04 +0200 |
commit | b21b9ba89cf66a8fac6f94efb79cfb425a2c4df2 (patch) | |
tree | 42047f997cda3eddec9faeafeb74435cc72a4786 /sys/src/cmd/hjfs/buf.c | |
parent | ef1c1863051d0530a31b291f4e334ee7601c318c (diff) |
added hjfs
Diffstat (limited to 'sys/src/cmd/hjfs/buf.c')
-rw-r--r-- | sys/src/cmd/hjfs/buf.c | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/sys/src/cmd/hjfs/buf.c b/sys/src/cmd/hjfs/buf.c new file mode 100644 index 000000000..23f533520 --- /dev/null +++ b/sys/src/cmd/hjfs/buf.c @@ -0,0 +1,314 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include "dat.h" +#include "fns.h" + +Channel *getb, *putb, *syncb; +Buf bfree; +BufReq *freereq, *freereqlast; + +static void +markbusy(Buf *b) +{ + b->busy = 1; + if(b->fnext != nil){ + b->fnext->fprev = b->fprev; + b->fprev->fnext = b->fnext; + b->fnext = b->fprev = nil; + } +} + +static void +markfree(Buf *b) +{ + b->busy = 0; + b->fnext = &bfree; + b->fprev = bfree.fprev; + b->fnext->fprev = b; + b->fprev->fnext = b; +} + +static void +changedev(Buf *b, Dev *d, uvlong off) +{ + if(b->dnext != nil){ + b->dnext->dprev = b->dprev; + b->dprev->dnext = b->dnext; + b->dprev = nil; + b->dnext = nil; + } + b->off = off; + b->d = d; + if(d != nil){ + b->dnext = &d->buf[b->off & BUFHASH]; + b->dprev = b->dnext->dprev; + b->dnext->dprev = b; + b->dprev->dnext = b; + } +} + +static void +delayreq(BufReq req, BufReq **first, BufReq **last) +{ + BufReq *r; + + r = emalloc(sizeof(*r)); + memcpy(r, &req, sizeof(*r)); + r->next = nil; + if(*first == nil) + *first = *last = r; + else{ + (*last)->next = r; + *last = r; + } +} + +static void +work(Dev *d, Buf *b) +{ + qlock(&d->workl); + b->wnext = &d->work; + b->wprev = b->wnext->wprev; + b->wnext->wprev = b; + b->wprev->wnext = b; + rwakeup(&d->workr); + qunlock(&d->workl); +} + +static void +givebuf(BufReq req, Buf *b) +{ + Buf *c, *l; + + markbusy(b); + if(req.d == b->d && req.off == b->off){ + send(req.resp, &b); + return; + } + if(b->op & BDELWRI){ + b->op &= ~BDELWRI; + b->op |= BWRITE; + delayreq(req, &b->next, &b->last); + b->resp = putb; + work(b->d, b); + return; + } + l = &req.d->buf[req.off & BUFHASH]; + for(c = l->dnext; c != l; c = c->dnext) + if(c->off == req.off) + abort(); + changedev(b, req.d, req.off); + b->op &= ~(BWRITE|BDELWRI|BWRIM); + if(req.nodata) + send(req.resp, &b); + else{ + b->resp = req.resp; + work(b->d, b); + } +} + +static void +undelayreq(Buf *b, BufReq **first, BufReq **last) +{ + BufReq *r; + + r = *first; + *first = r->next; + if(*last == r) + *last = nil; + givebuf(*r, b); + free(r); +} + +static void +handleget(BufReq req) +{ + Buf *b, *l; + Dev *d; + + d = req.d; + l = &d->buf[req.off & BUFHASH]; + for(b = l->dnext; b != l; b = b->dnext) + if(b->off == req.off){ + if(b->busy){ + delayreq(req, &b->next, &b->last); + return; + } + givebuf(req, b); + return; + } + if(bfree.fnext == &bfree){ + delayreq(req, &freereq, &freereqlast); + return; + } + b = bfree.fnext; + givebuf(req, b); +} + +static void +handleput(Buf *b) +{ + if(b->op & BWRIM){ + b->op &= ~(BWRIM | BDELWRI); + b->op |= BWRITE; + b->resp = putb; + work(b->d, b); + return; + } + if(b->error != nil){ + b->error = nil; + b->op &= ~BDELWRI; + changedev(b, nil, -1); + } + b->op &= ~BWRITE; + markfree(b); + if(b->next != nil) + undelayreq(b, &b->next, &b->last); + else if(freereq != nil) + undelayreq(b, &freereq, &freereqlast); +} + +static void +handlesync(Channel *resp) +{ + Buf *b, *c; + + for(b = bfree.fnext; b != &bfree; b = c){ + c = b->fnext; + if(b->d != nil && b->op & BDELWRI){ + markbusy(b); + b->resp = putb; + b->op &= ~BDELWRI; + b->op |= BWRITE; + work(b->d, b); + } + } + if(resp != nil) + sendp(resp, nil); +} + +static void +bufproc(void *) +{ + BufReq req; + Buf *buf; + Channel *r; + Alt a[] = {{getb, &req, CHANRCV}, {putb, &buf, CHANRCV}, {syncb, &r, CHANRCV}, {nil, nil, CHANEND}}; + + workerinit(); + for(;;) + switch(alt(a)){ + case 0: + handleget(req); + break; + case 1: + handleput(buf); + break; + case 2: + handlesync(r); + break; + case -1: + sysfatal("alt: %r"); + } +} + +static char * +typenames[] = { + [TRAW] "raw", + [TSUPERBLOCK] "superblock", + [TDENTRY] "dentry", + [TINDIR] "indir", + [TREF] "ref", + nil +}; + +static int +Tfmt(Fmt *f) +{ + int t; + + t = va_arg(f->args, uint); + if(t >= nelem(typenames) || typenames[t] == nil) + return fmtprint(f, "??? (%d)", t); + return fmtstrcpy(f, typenames[t]); +} + +void +bufinit(int nbuf) +{ + Buf *b; + + fmtinstall('T', Tfmt); + b = emalloc(sizeof(*b) * nbuf); + bfree.fnext = bfree.fprev = &bfree; + while(nbuf--) + markfree(b++); + getb = chancreate(sizeof(BufReq), 0); + putb = chancreate(sizeof(Buf *), 32); + syncb = chancreate(sizeof(ulong), 0); + proccreate(bufproc, nil, mainstacksize); +} + +Buf * +getbuf(Dev *d, uvlong off, int type, int nodata) +{ + ThrData *th; + BufReq req; + Buf *b; + + if(off >= d->size) + abort(); + th = getthrdata(); + req.d = d; + req.off = off; + req.resp = th->resp; + req.nodata = nodata; + send(getb, &req); + recv(th->resp, &b); + if(nodata) + b->type = type; + if(b->type != type && type != -1){ + dprint("hjfs: type mismatch, dev %s, block %lld, got %T, want %T, caller %#p\n", d->name, off, b->type, type, getcallerpc(&d)); + werrstr("phase error -- type mismatch"); + putbuf(b); + return nil; + } + if(b->error != nil){ + werrstr("%s", b->error); + putbuf(b); + return nil; + } + b->callerpc = getcallerpc(&d); + return b; +} + +void +putbuf(Buf *b) +{ + send(putb, &b); +} + +void +sync(int wait) +{ + Channel *r; + Dev *d; + Buf b; + + r = nil; + if(wait) + r = getthrdata()->resp; + sendp(syncb, r); + memset(&b, 0, sizeof(Buf)); + if(wait){ + recvp(r); + for(d = devs; d != nil; d = d->next){ + b.d = nil; + b.resp = r; + b.busy = 1; + work(d, &b); + recvp(r); + } + } +} |