xref: /plan9/sys/src/cmd/cfs/bcache.c (revision 41fb754a868aff65c81b63b0b07ae1fab2010fd9)
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