13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include "cformat.h"
43e12c5d1SDavid du Colombier #include "lru.h"
53e12c5d1SDavid du Colombier #include "bcache.h"
63e12c5d1SDavid du Colombier
73e12c5d1SDavid du Colombier int
bcinit(Bcache * bc,int f,int bsize)83e12c5d1SDavid du Colombier bcinit(Bcache *bc, int f, int bsize)
93e12c5d1SDavid du Colombier {
103e12c5d1SDavid du Colombier Bbuf *b;
113e12c5d1SDavid du Colombier
123e12c5d1SDavid du Colombier /*
133e12c5d1SDavid du Colombier * allocate space for all buffers
143e12c5d1SDavid du Colombier * point all buffers into outer space
153e12c5d1SDavid du Colombier */
163e12c5d1SDavid du Colombier bc->dfirst = 0;
173e12c5d1SDavid du Colombier bc->bsize = bsize;
183e12c5d1SDavid du Colombier bc->f = f;
193e12c5d1SDavid du Colombier lruinit(bc);
203e12c5d1SDavid du Colombier for(b = bc->bb; b < &bc->bb[Nbcache]; b++){
213e12c5d1SDavid du Colombier b->inuse = 0;
223e12c5d1SDavid du Colombier b->next = 0;
233e12c5d1SDavid du Colombier b->dirty = 0;
243e12c5d1SDavid du Colombier if(b->data == 0)
253e12c5d1SDavid du Colombier b->data = (char *)malloc(bc->bsize);
263e12c5d1SDavid du Colombier if(b->data == 0)
273e12c5d1SDavid du Colombier return -1;
283e12c5d1SDavid du Colombier lruadd(bc, b);
293e12c5d1SDavid du Colombier }
303e12c5d1SDavid du Colombier
313e12c5d1SDavid du Colombier return 0;
323e12c5d1SDavid du Colombier }
333e12c5d1SDavid du Colombier
343e12c5d1SDavid du Colombier /*
353e12c5d1SDavid du Colombier * Find a buffer for block b. If it's dirty, write it out.
363e12c5d1SDavid du Colombier */
373e12c5d1SDavid du Colombier Bbuf *
bcfind(Bcache * bc,ulong bno)383e12c5d1SDavid du Colombier bcfind(Bcache *bc, ulong bno)
393e12c5d1SDavid du Colombier {
403e12c5d1SDavid du Colombier Bbuf *b;
413e12c5d1SDavid du Colombier
423e12c5d1SDavid du Colombier if(bno == Notabno)
433e12c5d1SDavid du Colombier error("bcfind: Notabno");
443e12c5d1SDavid du Colombier bno &= ~Indbno;
453e12c5d1SDavid du Colombier
463e12c5d1SDavid du Colombier /*
473e12c5d1SDavid du Colombier * if we already have a buffer for this bno, use it
483e12c5d1SDavid du Colombier */
49*41fb754aSDavid du Colombier for(b = bc->bb; b < &bc->bb[Nbcache]; b++)
503e12c5d1SDavid du Colombier if(b->inuse && b->bno==bno)
513e12c5d1SDavid du Colombier goto out;
523e12c5d1SDavid du Colombier
533e12c5d1SDavid du Colombier /*
543e12c5d1SDavid du Colombier * get least recently used block
553e12c5d1SDavid du Colombier */
563e12c5d1SDavid du Colombier b = (Bbuf*)bc->lnext;
573e12c5d1SDavid du Colombier out:
583e12c5d1SDavid du Colombier /*
593e12c5d1SDavid du Colombier * if dirty, write it out
603e12c5d1SDavid du Colombier */
61*41fb754aSDavid du Colombier if(b->dirty)
623e12c5d1SDavid du Colombier if(bcwrite(bc, b) < 0)
633e12c5d1SDavid du Colombier warning("writing dirty page");
643e12c5d1SDavid du Colombier lruref(bc, b);
653e12c5d1SDavid du Colombier return b;
663e12c5d1SDavid du Colombier }
673e12c5d1SDavid du Colombier
683e12c5d1SDavid du Colombier /*
693e12c5d1SDavid du Colombier * allocate a buffer block for a block. it's guaranteed to be there till
703e12c5d1SDavid du Colombier * the next Nbcache bcread's.
713e12c5d1SDavid du Colombier */
723e12c5d1SDavid du Colombier Bbuf *
bcalloc(Bcache * bc,ulong bno)733e12c5d1SDavid du Colombier bcalloc(Bcache *bc, ulong bno)
743e12c5d1SDavid du Colombier {
753e12c5d1SDavid du Colombier Bbuf *b;
763e12c5d1SDavid du Colombier
773e12c5d1SDavid du Colombier b = bcfind(bc, bno);
783e12c5d1SDavid du Colombier bno &= ~Indbno;
793e12c5d1SDavid du Colombier b->bno = bno;
803e12c5d1SDavid du Colombier b->inuse = 1;
813e12c5d1SDavid du Colombier return b;
823e12c5d1SDavid du Colombier }
833e12c5d1SDavid du Colombier
843e12c5d1SDavid du Colombier /*
853e12c5d1SDavid du Colombier * read a block into a buffer cache. it's guaranteed to be there till
863e12c5d1SDavid du Colombier * the next Nbcache bcread's.
873e12c5d1SDavid du Colombier */
883e12c5d1SDavid du Colombier Bbuf *
bcread(Bcache * bc,ulong bno)893e12c5d1SDavid du Colombier bcread(Bcache *bc, ulong bno)
903e12c5d1SDavid du Colombier {
913e12c5d1SDavid du Colombier Bbuf *b;
923e12c5d1SDavid du Colombier
933e12c5d1SDavid du Colombier b = bcfind(bc, bno);
943e12c5d1SDavid du Colombier bno &= ~Indbno;
95*41fb754aSDavid du Colombier if(b->bno!=bno || !b->inuse)
963e12c5d1SDavid du Colombier /*
973e12c5d1SDavid du Colombier * read in the one we really want
983e12c5d1SDavid du Colombier */
993e12c5d1SDavid du Colombier if(bread(bc, bno, b->data) < 0){
1003e12c5d1SDavid du Colombier b->inuse = 0;
1013e12c5d1SDavid du Colombier return 0;
1023e12c5d1SDavid du Colombier }
1033e12c5d1SDavid du Colombier b->bno = bno;
1043e12c5d1SDavid du Colombier b->inuse = 1;
1053e12c5d1SDavid du Colombier return b;
1063e12c5d1SDavid du Colombier }
1073e12c5d1SDavid du Colombier
1083e12c5d1SDavid du Colombier /*
1093e12c5d1SDavid du Colombier * mark a page dirty, if it's already dirty force a write
1103e12c5d1SDavid du Colombier *
1113e12c5d1SDavid du Colombier * N.B: ordering is important.
1123e12c5d1SDavid du Colombier */
1133e12c5d1SDavid du Colombier void
bcmark(Bcache * bc,Bbuf * b)1143e12c5d1SDavid du Colombier bcmark(Bcache *bc, Bbuf *b)
1153e12c5d1SDavid du Colombier {
1163e12c5d1SDavid du Colombier lruref(bc, b);
1173e12c5d1SDavid du Colombier
1183e12c5d1SDavid du Colombier if(b->dirty){
1193e12c5d1SDavid du Colombier bcwrite(bc, b);
1203e12c5d1SDavid du Colombier return;
1213e12c5d1SDavid du Colombier }
1223e12c5d1SDavid du Colombier
1233e12c5d1SDavid du Colombier b->dirty = 1;
1243e12c5d1SDavid du Colombier if(bc->dfirst)
1253e12c5d1SDavid du Colombier bc->dlast->next = b;
1263e12c5d1SDavid du Colombier else
1273e12c5d1SDavid du Colombier bc->dfirst = b;
1283e12c5d1SDavid du Colombier bc->dlast = b;
1293e12c5d1SDavid du Colombier }
1303e12c5d1SDavid du Colombier
1313e12c5d1SDavid du Colombier /*
132*41fb754aSDavid du Colombier * write out a page (and all preceding dirty ones)
1333e12c5d1SDavid du Colombier */
1343e12c5d1SDavid du Colombier int
bcwrite(Bcache * bc,Bbuf * b)1353e12c5d1SDavid du Colombier bcwrite(Bcache *bc, Bbuf *b)
1363e12c5d1SDavid du Colombier {
1373e12c5d1SDavid du Colombier Bbuf *nb;
1383e12c5d1SDavid du Colombier
1393e12c5d1SDavid du Colombier /*
140*41fb754aSDavid du Colombier * write out all preceding pages
1413e12c5d1SDavid du Colombier */
1423e12c5d1SDavid du Colombier while(nb = bc->dfirst){
1433e12c5d1SDavid du Colombier if(bwrite(bc, nb->bno, nb->data) < 0)
1443e12c5d1SDavid du Colombier return -1;
1453e12c5d1SDavid du Colombier nb->dirty = 0;
1463e12c5d1SDavid du Colombier bc->dfirst = nb->next;
1473e12c5d1SDavid du Colombier nb->next = 0;
1483e12c5d1SDavid du Colombier if(nb == b)
1493e12c5d1SDavid du Colombier return 0;
1503e12c5d1SDavid du Colombier }
1513e12c5d1SDavid du Colombier
1523e12c5d1SDavid du Colombier /*
1533e12c5d1SDavid du Colombier * write out this page
1543e12c5d1SDavid du Colombier */
1553e12c5d1SDavid du Colombier if(bwrite(bc, b->bno, b->data) < 0)
1563e12c5d1SDavid du Colombier return -1;
1573e12c5d1SDavid du Colombier b->dirty = 0;
1583e12c5d1SDavid du Colombier b->next = 0;
1593e12c5d1SDavid du Colombier return 0;
1603e12c5d1SDavid du Colombier }
1613e12c5d1SDavid du Colombier
1623e12c5d1SDavid du Colombier /*
1633e12c5d1SDavid du Colombier * write out all dirty pages (in order)
1643e12c5d1SDavid du Colombier */
1653e12c5d1SDavid du Colombier int
bcsync(Bcache * bc)1663e12c5d1SDavid du Colombier bcsync(Bcache *bc)
1673e12c5d1SDavid du Colombier {
1683e12c5d1SDavid du Colombier if(bc->dfirst)
1693e12c5d1SDavid du Colombier return bcwrite(bc, bc->dlast);
1703e12c5d1SDavid du Colombier return 0;
1713e12c5d1SDavid du Colombier }
1723e12c5d1SDavid du Colombier
1733e12c5d1SDavid du Colombier /*
1743e12c5d1SDavid du Colombier * read a block from disk
1753e12c5d1SDavid du Colombier */
1763e12c5d1SDavid du Colombier int
bread(Bcache * bc,ulong bno,void * buf)1773e12c5d1SDavid du Colombier bread(Bcache *bc, ulong bno, void *buf)
1783e12c5d1SDavid du Colombier {
179*41fb754aSDavid du Colombier uvlong x = (uvlong)bno * bc->bsize;
1803e12c5d1SDavid du Colombier
1819a747e4fSDavid du Colombier if(pread(bc->f, buf, bc->bsize, x) != bc->bsize)
1823e12c5d1SDavid du Colombier return -1;
1833e12c5d1SDavid du Colombier return 0;
1843e12c5d1SDavid du Colombier }
1853e12c5d1SDavid du Colombier
1863e12c5d1SDavid du Colombier /*
1873e12c5d1SDavid du Colombier * write a block to disk
1883e12c5d1SDavid du Colombier */
1893e12c5d1SDavid du Colombier int
bwrite(Bcache * bc,ulong bno,void * buf)1903e12c5d1SDavid du Colombier bwrite(Bcache *bc, ulong bno, void *buf)
1913e12c5d1SDavid du Colombier {
192*41fb754aSDavid du Colombier uvlong x = (uvlong)bno * bc->bsize;
1933e12c5d1SDavid du Colombier
1949a747e4fSDavid du Colombier if(pwrite(bc->f, buf, bc->bsize, x) != bc->bsize)
1953e12c5d1SDavid du Colombier return -1;
1963e12c5d1SDavid du Colombier return 0;
1973e12c5d1SDavid du Colombier }
198