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