123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- #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;
- }
|