xref: /plan9-contrib/sys/src/cmd/ramcfs/bcache.c (revision 206fef1c8a79725587ecb1892b58204f8235c098)
1*206fef1cSDavid du Colombier #include <u.h>
2*206fef1cSDavid du Colombier #include <libc.h>
3*206fef1cSDavid du Colombier #include "cformat.h"
4*206fef1cSDavid du Colombier #include "lru.h"
5*206fef1cSDavid du Colombier #include "bcache.h"
6*206fef1cSDavid du Colombier 
7*206fef1cSDavid du Colombier int
bcinit(Bcache * bc,char * mc,int bsize)8*206fef1cSDavid du Colombier bcinit(Bcache *bc, char *mc, int bsize)
9*206fef1cSDavid du Colombier {
10*206fef1cSDavid du Colombier 	Bbuf *b;
11*206fef1cSDavid du Colombier 
12*206fef1cSDavid du Colombier 	/*
13*206fef1cSDavid du Colombier 	 *  allocate space for all buffers
14*206fef1cSDavid du Colombier 	 *  point all buffers into outer space
15*206fef1cSDavid du Colombier 	 */
16*206fef1cSDavid du Colombier 	bc->dfirst = 0;
17*206fef1cSDavid du Colombier 	bc->bsize = bsize;
18*206fef1cSDavid du Colombier 	bc->memcache = mc;
19*206fef1cSDavid du Colombier 	lruinit(bc);
20*206fef1cSDavid du Colombier 	for(b = bc->bb; b < &bc->bb[Nbcache]; b++){
21*206fef1cSDavid du Colombier 		b->inuse = 0;
22*206fef1cSDavid du Colombier 		b->next = 0;
23*206fef1cSDavid du Colombier 		b->dirty = 0;
24*206fef1cSDavid du Colombier 		if(b->data == 0)
25*206fef1cSDavid du Colombier 			b->data = (char *)malloc(bc->bsize);
26*206fef1cSDavid du Colombier 		if(b->data == 0)
27*206fef1cSDavid du Colombier 			return -1;
28*206fef1cSDavid du Colombier 		lruadd(bc, b);
29*206fef1cSDavid du Colombier 	}
30*206fef1cSDavid du Colombier 
31*206fef1cSDavid du Colombier 	return 0;
32*206fef1cSDavid du Colombier }
33*206fef1cSDavid du Colombier 
34*206fef1cSDavid du Colombier /*
35*206fef1cSDavid du Colombier  *  Find a buffer for block b.  If it's dirty, write it out.
36*206fef1cSDavid du Colombier  */
37*206fef1cSDavid du Colombier Bbuf *
bcfind(Bcache * bc,ulong bno)38*206fef1cSDavid du Colombier bcfind(Bcache *bc, ulong bno)
39*206fef1cSDavid du Colombier {
40*206fef1cSDavid du Colombier 	Bbuf *b;
41*206fef1cSDavid du Colombier 
42*206fef1cSDavid du Colombier 	if(bno == Notabno)
43*206fef1cSDavid du Colombier 		error("bcfind: Notabno");
44*206fef1cSDavid du Colombier 	bno &= ~Indbno;
45*206fef1cSDavid du Colombier 
46*206fef1cSDavid du Colombier 	/*
47*206fef1cSDavid du Colombier 	 *  if we already have a buffer for this bno, use it
48*206fef1cSDavid du Colombier 	 */
49*206fef1cSDavid du Colombier 	for(b = bc->bb; b < &bc->bb[Nbcache]; b++)
50*206fef1cSDavid du Colombier 		if(b->inuse && b->bno==bno)
51*206fef1cSDavid du Colombier 			goto out;
52*206fef1cSDavid du Colombier 
53*206fef1cSDavid du Colombier 	/*
54*206fef1cSDavid du Colombier 	 *  get least recently used block
55*206fef1cSDavid du Colombier 	 */
56*206fef1cSDavid du Colombier 	b = (Bbuf*)bc->lnext;
57*206fef1cSDavid du Colombier out:
58*206fef1cSDavid du Colombier 	/*
59*206fef1cSDavid du Colombier 	 *  if dirty, write it out
60*206fef1cSDavid du Colombier 	 */
61*206fef1cSDavid du Colombier 	if(b->dirty)
62*206fef1cSDavid du Colombier 		if(bcwrite(bc, b) < 0)
63*206fef1cSDavid du Colombier 			warning("writing dirty page");
64*206fef1cSDavid du Colombier 	lruref(bc, b);
65*206fef1cSDavid du Colombier 	return b;
66*206fef1cSDavid du Colombier }
67*206fef1cSDavid du Colombier 
68*206fef1cSDavid du Colombier /*
69*206fef1cSDavid du Colombier  *  allocate a buffer block for a block.  it's guaranteed to be there till
70*206fef1cSDavid du Colombier  *  the next Nbcache bcread's.
71*206fef1cSDavid du Colombier  */
72*206fef1cSDavid du Colombier Bbuf *
bcalloc(Bcache * bc,ulong bno)73*206fef1cSDavid du Colombier bcalloc(Bcache *bc, ulong bno)
74*206fef1cSDavid du Colombier {
75*206fef1cSDavid du Colombier 	Bbuf *b;
76*206fef1cSDavid du Colombier 
77*206fef1cSDavid du Colombier 	b = bcfind(bc, bno);
78*206fef1cSDavid du Colombier 	bno &= ~Indbno;
79*206fef1cSDavid du Colombier 	b->bno = bno;
80*206fef1cSDavid du Colombier 	b->inuse = 1;
81*206fef1cSDavid du Colombier 	return b;
82*206fef1cSDavid du Colombier }
83*206fef1cSDavid du Colombier 
84*206fef1cSDavid du Colombier /*
85*206fef1cSDavid du Colombier  *  read a block into a buffer cache.  it's guaranteed to be there till
86*206fef1cSDavid du Colombier  *  the next Nbcache bcread's.
87*206fef1cSDavid du Colombier  */
88*206fef1cSDavid du Colombier Bbuf *
bcread(Bcache * bc,ulong bno)89*206fef1cSDavid du Colombier bcread(Bcache *bc, ulong bno)
90*206fef1cSDavid du Colombier {
91*206fef1cSDavid du Colombier 	Bbuf *b;
92*206fef1cSDavid du Colombier 
93*206fef1cSDavid du Colombier 	b = bcfind(bc, bno);
94*206fef1cSDavid du Colombier 	bno &= ~Indbno;
95*206fef1cSDavid du Colombier 	if(b->bno!=bno || !b->inuse)
96*206fef1cSDavid du Colombier 		/*
97*206fef1cSDavid du Colombier 		 *  read in the one we really want
98*206fef1cSDavid du Colombier 		 */
99*206fef1cSDavid du Colombier 		if(bread(bc, bno, b->data) < 0){
100*206fef1cSDavid du Colombier 			b->inuse = 0;
101*206fef1cSDavid du Colombier 			return 0;
102*206fef1cSDavid du Colombier 		}
103*206fef1cSDavid du Colombier 	b->bno = bno;
104*206fef1cSDavid du Colombier 	b->inuse = 1;
105*206fef1cSDavid du Colombier 	return b;
106*206fef1cSDavid du Colombier }
107*206fef1cSDavid du Colombier 
108*206fef1cSDavid du Colombier /*
109*206fef1cSDavid du Colombier  *  mark a page dirty, if it's already dirty force a write
110*206fef1cSDavid du Colombier  *
111*206fef1cSDavid du Colombier  *	N.B: ordering is important.
112*206fef1cSDavid du Colombier  */
113*206fef1cSDavid du Colombier void
bcmark(Bcache * bc,Bbuf * b)114*206fef1cSDavid du Colombier bcmark(Bcache *bc, Bbuf *b)
115*206fef1cSDavid du Colombier {
116*206fef1cSDavid du Colombier 	lruref(bc, b);
117*206fef1cSDavid du Colombier 
118*206fef1cSDavid du Colombier 	if(b->dirty){
119*206fef1cSDavid du Colombier 		bcwrite(bc, b);
120*206fef1cSDavid du Colombier 		return;
121*206fef1cSDavid du Colombier 	}
122*206fef1cSDavid du Colombier 
123*206fef1cSDavid du Colombier 	b->dirty = 1;
124*206fef1cSDavid du Colombier 	if(bc->dfirst)
125*206fef1cSDavid du Colombier 		bc->dlast->next = b;
126*206fef1cSDavid du Colombier 	else
127*206fef1cSDavid du Colombier 		bc->dfirst = b;
128*206fef1cSDavid du Colombier 	bc->dlast = b;
129*206fef1cSDavid du Colombier }
130*206fef1cSDavid du Colombier 
131*206fef1cSDavid du Colombier /*
132*206fef1cSDavid du Colombier  *  write out a page (and all preceding dirty ones)
133*206fef1cSDavid du Colombier  */
134*206fef1cSDavid du Colombier int
bcwrite(Bcache * bc,Bbuf * b)135*206fef1cSDavid du Colombier bcwrite(Bcache *bc, Bbuf *b)
136*206fef1cSDavid du Colombier {
137*206fef1cSDavid du Colombier 	Bbuf *nb;
138*206fef1cSDavid du Colombier 
139*206fef1cSDavid du Colombier 	/*
140*206fef1cSDavid du Colombier 	 *  write out all preceding pages
141*206fef1cSDavid du Colombier 	 */
142*206fef1cSDavid du Colombier 	while(nb = bc->dfirst){
143*206fef1cSDavid du Colombier 		if(bwrite(bc, nb->bno, nb->data) < 0)
144*206fef1cSDavid du Colombier 			return -1;
145*206fef1cSDavid du Colombier 		nb->dirty = 0;
146*206fef1cSDavid du Colombier 		bc->dfirst = nb->next;
147*206fef1cSDavid du Colombier 		nb->next = 0;
148*206fef1cSDavid du Colombier 		if(nb == b)
149*206fef1cSDavid du Colombier 			return 0;
150*206fef1cSDavid du Colombier 	}
151*206fef1cSDavid du Colombier 
152*206fef1cSDavid du Colombier 	/*
153*206fef1cSDavid du Colombier 	 *  write out this page
154*206fef1cSDavid du Colombier 	 */
155*206fef1cSDavid du Colombier 	if(bwrite(bc, b->bno, b->data) < 0)
156*206fef1cSDavid du Colombier 		return -1;
157*206fef1cSDavid du Colombier 	b->dirty = 0;
158*206fef1cSDavid du Colombier 	b->next = 0;
159*206fef1cSDavid du Colombier 	return 0;
160*206fef1cSDavid du Colombier }
161*206fef1cSDavid du Colombier 
162*206fef1cSDavid du Colombier /*
163*206fef1cSDavid du Colombier  *  write out all dirty pages (in order)
164*206fef1cSDavid du Colombier  */
165*206fef1cSDavid du Colombier int
bcsync(Bcache * bc)166*206fef1cSDavid du Colombier bcsync(Bcache *bc)
167*206fef1cSDavid du Colombier {
168*206fef1cSDavid du Colombier 	if(bc->dfirst)
169*206fef1cSDavid du Colombier 		return bcwrite(bc, bc->dlast);
170*206fef1cSDavid du Colombier 	return 0;
171*206fef1cSDavid du Colombier }
172*206fef1cSDavid du Colombier 
173*206fef1cSDavid du Colombier /*
174*206fef1cSDavid du Colombier  *  read a block from memory cache
175*206fef1cSDavid du Colombier  */
176*206fef1cSDavid du Colombier int
bread(Bcache * bc,ulong bno,void * buf)177*206fef1cSDavid du Colombier bread(Bcache *bc, ulong bno, void *buf)
178*206fef1cSDavid du Colombier {
179*206fef1cSDavid du Colombier 	uvlong x = (uvlong)bno * bc->bsize;
180*206fef1cSDavid du Colombier 
181*206fef1cSDavid du Colombier 	if (x > cachesize - bc->bsize)
182*206fef1cSDavid du Colombier 		return -1;
183*206fef1cSDavid du Colombier 	memmove(buf, bc->memcache + x, bc->bsize);
184*206fef1cSDavid du Colombier 	return 0;
185*206fef1cSDavid du Colombier }
186*206fef1cSDavid du Colombier 
187*206fef1cSDavid du Colombier /*
188*206fef1cSDavid du Colombier  *  write a block to memory cache
189*206fef1cSDavid du Colombier  */
190*206fef1cSDavid du Colombier int
bwrite(Bcache * bc,ulong bno,void * buf)191*206fef1cSDavid du Colombier bwrite(Bcache *bc, ulong bno, void *buf)
192*206fef1cSDavid du Colombier {
193*206fef1cSDavid du Colombier 	uvlong x = (uvlong)bno * bc->bsize;
194*206fef1cSDavid du Colombier 
195*206fef1cSDavid du Colombier 	if (x > cachesize - bc->bsize)
196*206fef1cSDavid du Colombier 		return -1;
197*206fef1cSDavid du Colombier 	memmove(bc->memcache + x, buf, bc->bsize);
198*206fef1cSDavid du Colombier 	return 0;
199*206fef1cSDavid du Colombier }
200