diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/cfs/bcache.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cfs/bcache.c')
-rwxr-xr-x | sys/src/cmd/cfs/bcache.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/sys/src/cmd/cfs/bcache.c b/sys/src/cmd/cfs/bcache.c new file mode 100755 index 000000000..becd675ea --- /dev/null +++ b/sys/src/cmd/cfs/bcache.c @@ -0,0 +1,197 @@ +#include <u.h> +#include <libc.h> +#include "cformat.h" +#include "lru.h" +#include "bcache.h" + +int +bcinit(Bcache *bc, int f, int bsize) +{ + Bbuf *b; + + /* + * allocate space for all buffers + * point all buffers into outer space + */ + bc->dfirst = 0; + bc->bsize = bsize; + bc->f = f; + lruinit(bc); + for(b = bc->bb; b < &bc->bb[Nbcache]; b++){ + b->inuse = 0; + b->next = 0; + b->dirty = 0; + if(b->data == 0) + b->data = (char *)malloc(bc->bsize); + if(b->data == 0) + return -1; + lruadd(bc, b); + } + + return 0; +} + +/* + * Find a buffer for block b. If it's dirty, write it out. + */ +Bbuf * +bcfind(Bcache *bc, ulong bno) +{ + Bbuf *b; + + if(bno == Notabno) + error("bcfind: Notabno"); + bno &= ~Indbno; + + /* + * if we already have a buffer for this bno, use it + */ + for(b = bc->bb; b < &bc->bb[Nbcache]; b++) + if(b->inuse && b->bno==bno) + goto out; + + /* + * get least recently used block + */ + b = (Bbuf*)bc->lnext; +out: + /* + * if dirty, write it out + */ + if(b->dirty) + if(bcwrite(bc, b) < 0) + warning("writing dirty page"); + lruref(bc, b); + return b; +} + +/* + * allocate a buffer block for a block. it's guaranteed to be there till + * the next Nbcache bcread's. + */ +Bbuf * +bcalloc(Bcache *bc, ulong bno) +{ + Bbuf *b; + + b = bcfind(bc, bno); + bno &= ~Indbno; + b->bno = bno; + b->inuse = 1; + return b; +} + +/* + * read a block into a buffer cache. it's guaranteed to be there till + * the next Nbcache bcread's. + */ +Bbuf * +bcread(Bcache *bc, ulong bno) +{ + Bbuf *b; + + b = bcfind(bc, bno); + bno &= ~Indbno; + if(b->bno!=bno || !b->inuse) + /* + * read in the one we really want + */ + if(bread(bc, bno, b->data) < 0){ + b->inuse = 0; + return 0; + } + b->bno = bno; + b->inuse = 1; + return b; +} + +/* + * mark a page dirty, if it's already dirty force a write + * + * N.B: ordering is important. + */ +void +bcmark(Bcache *bc, Bbuf *b) +{ + lruref(bc, b); + + if(b->dirty){ + bcwrite(bc, b); + return; + } + + b->dirty = 1; + if(bc->dfirst) + bc->dlast->next = b; + else + bc->dfirst = b; + bc->dlast = b; +} + +/* + * write out a page (and all preceding dirty ones) + */ +int +bcwrite(Bcache *bc, Bbuf *b) +{ + Bbuf *nb; + + /* + * write out all preceding pages + */ + while(nb = bc->dfirst){ + if(bwrite(bc, nb->bno, nb->data) < 0) + return -1; + nb->dirty = 0; + bc->dfirst = nb->next; + nb->next = 0; + if(nb == b) + return 0; + } + + /* + * write out this page + */ + if(bwrite(bc, b->bno, b->data) < 0) + return -1; + b->dirty = 0; + b->next = 0; + return 0; +} + +/* + * write out all dirty pages (in order) + */ +int +bcsync(Bcache *bc) +{ + if(bc->dfirst) + return bcwrite(bc, bc->dlast); + return 0; +} + +/* + * read a block from disk + */ +int +bread(Bcache *bc, ulong bno, void *buf) +{ + uvlong x = (uvlong)bno * bc->bsize; + + if(pread(bc->f, buf, bc->bsize, x) != bc->bsize) + return -1; + return 0; +} + +/* + * write a block to disk + */ +int +bwrite(Bcache *bc, ulong bno, void *buf) +{ + uvlong x = (uvlong)bno * bc->bsize; + + if(pwrite(bc->f, buf, bc->bsize, x) != bc->bsize) + return -1; + return 0; +} |