206 lines · 3.3 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include "cformat.h"#include "lru.h"#include "bcache.h" intbcinit(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. */voidbcmark(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) */intbcwrite(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) */intbcsync(Bcache *bc){	if(bc->dfirst)		return bcwrite(bc, bc->dlast);	return 0;} /* *  read a block from disk */intbread(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 */intbwrite(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;}