xref: /plan9-contrib/sys/src/cmd/ramcfs/disk.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 #include "disk.h"
7*206fef1cSDavid du Colombier 
8*206fef1cSDavid du Colombier int	icformat(Disk*, ulong);
9*206fef1cSDavid du Colombier 
10*206fef1cSDavid du Colombier /*
11*206fef1cSDavid du Colombier  *  read in the disk structures,  return -1 if the format
12*206fef1cSDavid du Colombier  *  is inconsistent.
13*206fef1cSDavid du Colombier  */
14*206fef1cSDavid du Colombier int
dinit(Disk * d,char * mc,int psize,char * expname)15*206fef1cSDavid du Colombier dinit(Disk *d, char *mc, int psize, char *expname)
16*206fef1cSDavid du Colombier {
17*206fef1cSDavid du Colombier 	ulong	i;
18*206fef1cSDavid du Colombier 	uvlong	length;
19*206fef1cSDavid du Colombier 	char	buf[1024];
20*206fef1cSDavid du Colombier 	Bbuf	*b;
21*206fef1cSDavid du Colombier 	Dalloc	*ba;
22*206fef1cSDavid du Colombier 
23*206fef1cSDavid du Colombier 	/*
24*206fef1cSDavid du Colombier 	 *  get disk size
25*206fef1cSDavid du Colombier 	 */
26*206fef1cSDavid du Colombier 	length = cachesize;
27*206fef1cSDavid du Colombier 
28*206fef1cSDavid du Colombier 	/*
29*206fef1cSDavid du Colombier 	 *  read first physical block to get logical block size, # of inodes,
30*206fef1cSDavid du Colombier 	 *  and # of allocation blocks
31*206fef1cSDavid du Colombier 	 */
32*206fef1cSDavid du Colombier 	memmove(buf, mc, sizeof buf);
33*206fef1cSDavid du Colombier 
34*206fef1cSDavid du Colombier 	ba = (Dalloc*)buf;
35*206fef1cSDavid du Colombier 	if(ba->bsize <= 0){
36*206fef1cSDavid du Colombier 		fprint(2, "dinit: bsize 0x%lux<= 0\n", ba->bsize);
37*206fef1cSDavid du Colombier 		return -1;
38*206fef1cSDavid du Colombier 	}
39*206fef1cSDavid du Colombier 	if((ba->bsize % psize) != 0){
40*206fef1cSDavid du Colombier 		fprint(2, "dinit: logical bsize (%lud) not multiple of physical (%ud)\n",
41*206fef1cSDavid du Colombier 			ba->bsize, psize);
42*206fef1cSDavid du Colombier 		return -1;
43*206fef1cSDavid du Colombier 	}
44*206fef1cSDavid du Colombier 	d->bsize = ba->bsize;
45*206fef1cSDavid du Colombier 	d->nb = length/d->bsize;
46*206fef1cSDavid du Colombier 	d->b2b = (d->bsize - sizeof(Dahdr))*8;
47*206fef1cSDavid du Colombier 	d->nab = (d->nb+d->b2b-1)/d->b2b;
48*206fef1cSDavid du Colombier 	d->p2b = d->bsize/sizeof(Dptr);
49*206fef1cSDavid du Colombier 	strncpy(d->name, ba->name, sizeof d->name);
50*206fef1cSDavid du Colombier 
51*206fef1cSDavid du Colombier 	if (expname != nil && strncmp(d->name, expname, sizeof d->name) != 0) {
52*206fef1cSDavid du Colombier 		/* Mismatch with recorded name; fail here to force a format */
53*206fef1cSDavid du Colombier 		fprint(2, "%s: name mismatch\n", argv0);
54*206fef1cSDavid du Colombier 		return -1;
55*206fef1cSDavid du Colombier 	}
56*206fef1cSDavid du Colombier 
57*206fef1cSDavid du Colombier 	/*
58*206fef1cSDavid du Colombier 	 *  check allocation blocks for consistency
59*206fef1cSDavid du Colombier 	 */
60*206fef1cSDavid du Colombier 	if(bcinit(d, mc, d->bsize) < 0){
61*206fef1cSDavid du Colombier 		fprint(2, "%s: dinit: couldn't init block cache\n", argv0);
62*206fef1cSDavid du Colombier 		return -1;
63*206fef1cSDavid du Colombier 	}
64*206fef1cSDavid du Colombier 	for(i = 0; i < d->nab; i++){
65*206fef1cSDavid du Colombier 		b = bcread(d, i);
66*206fef1cSDavid du Colombier 		if(b == 0){
67*206fef1cSDavid du Colombier 			perror("dinit: read");
68*206fef1cSDavid du Colombier 			return -1;
69*206fef1cSDavid du Colombier 		}
70*206fef1cSDavid du Colombier 		ba = (Dalloc*)b->data;
71*206fef1cSDavid du Colombier 		if(ba->magic != Amagic){
72*206fef1cSDavid du Colombier 			fprint(2, "dinit: bad magic in alloc block %uld\n", i);
73*206fef1cSDavid du Colombier 			return -1;
74*206fef1cSDavid du Colombier 		}
75*206fef1cSDavid du Colombier 		if(d->bsize != ba->bsize){
76*206fef1cSDavid du Colombier 			fprint(2, "dinit: bad bsize in alloc block %uld\n", i);
77*206fef1cSDavid du Colombier 			return -1;
78*206fef1cSDavid du Colombier 		}
79*206fef1cSDavid du Colombier 		if(d->nab != ba->nab){
80*206fef1cSDavid du Colombier 			fprint(2, "dinit: bad nab in alloc block %uld\n", i);
81*206fef1cSDavid du Colombier 			return -1;
82*206fef1cSDavid du Colombier 		}
83*206fef1cSDavid du Colombier 		if(strncmp(d->name, ba->name, sizeof(d->name))){
84*206fef1cSDavid du Colombier 			fprint(2, "dinit: bad name in alloc block %uld\n", i);
85*206fef1cSDavid du Colombier 			return -1;
86*206fef1cSDavid du Colombier 		}
87*206fef1cSDavid du Colombier 	}
88*206fef1cSDavid du Colombier 	return 0;
89*206fef1cSDavid du Colombier }
90*206fef1cSDavid du Colombier 
91*206fef1cSDavid du Colombier /*
92*206fef1cSDavid du Colombier  *  format the allocated memory as a cache
93*206fef1cSDavid du Colombier  */
94*206fef1cSDavid du Colombier int
dformat(Disk * d,char * mc,char * name,ulong bsize,ulong psize)95*206fef1cSDavid du Colombier dformat(Disk *d, char *mc, char *name, ulong bsize, ulong psize)
96*206fef1cSDavid du Colombier {
97*206fef1cSDavid du Colombier 	int	i;
98*206fef1cSDavid du Colombier 	uvlong	length;
99*206fef1cSDavid du Colombier 	Bbuf	*b;
100*206fef1cSDavid du Colombier 	Dalloc	*ba;
101*206fef1cSDavid du Colombier 	Dptr	dptr;
102*206fef1cSDavid du Colombier 
103*206fef1cSDavid du Colombier 	fprint(2, "formatting memory\n");
104*206fef1cSDavid du Colombier 
105*206fef1cSDavid du Colombier 	/*
106*206fef1cSDavid du Colombier 	 *  calculate basic numbers
107*206fef1cSDavid du Colombier 	 */
108*206fef1cSDavid du Colombier 	length = cachesize;
109*206fef1cSDavid du Colombier 	d->bsize = bsize;
110*206fef1cSDavid du Colombier 	if((d->bsize % psize) != 0){
111*206fef1cSDavid du Colombier 		fprint(2, "%s: logical bsize not multiple of physical\n", argv0);
112*206fef1cSDavid du Colombier 		return -1;
113*206fef1cSDavid du Colombier 	}
114*206fef1cSDavid du Colombier 	d->nb = length/d->bsize;
115*206fef1cSDavid du Colombier 	d->b2b = (d->bsize - sizeof(Dahdr))*8;
116*206fef1cSDavid du Colombier 	d->nab = (d->nb+d->b2b-1)/d->b2b;
117*206fef1cSDavid du Colombier 	d->p2b = d->bsize/sizeof(Dptr);
118*206fef1cSDavid du Colombier 
119*206fef1cSDavid du Colombier 	/*
120*206fef1cSDavid du Colombier 	 *  init allocation blocks
121*206fef1cSDavid du Colombier 	 */
122*206fef1cSDavid du Colombier 	if(bcinit(d, mc, d->bsize) < 0)
123*206fef1cSDavid du Colombier 		return -1;
124*206fef1cSDavid du Colombier 	for(i = 0; i < d->nab; i++){
125*206fef1cSDavid du Colombier 		b = bcalloc(d, i);
126*206fef1cSDavid du Colombier 		if(b == 0){
127*206fef1cSDavid du Colombier 			perror("cfs: bcalloc");
128*206fef1cSDavid du Colombier 			return -1;
129*206fef1cSDavid du Colombier 		}
130*206fef1cSDavid du Colombier 		memset(b->data, 0, d->bsize);
131*206fef1cSDavid du Colombier 		ba = (Dalloc*)b->data;
132*206fef1cSDavid du Colombier 		ba->magic = Amagic;
133*206fef1cSDavid du Colombier 		ba->bsize = d->bsize;
134*206fef1cSDavid du Colombier 		ba->nab = d->nab;
135*206fef1cSDavid du Colombier 		strncpy(ba->name, name, sizeof(ba->name));
136*206fef1cSDavid du Colombier 		bcmark(d, b);
137*206fef1cSDavid du Colombier 	}
138*206fef1cSDavid du Colombier 
139*206fef1cSDavid du Colombier 	/*
140*206fef1cSDavid du Colombier 	 *  allocate allocation blocks
141*206fef1cSDavid du Colombier 	 */
142*206fef1cSDavid du Colombier 	for(i = 0; i < d->nab; i++)
143*206fef1cSDavid du Colombier 		if(dalloc(d, &dptr) == Notabno){
144*206fef1cSDavid du Colombier 			fprint(2, "can't allocate allocation blocks\n");
145*206fef1cSDavid du Colombier 			return -1;
146*206fef1cSDavid du Colombier 		}
147*206fef1cSDavid du Colombier 
148*206fef1cSDavid du Colombier 	return bcsync(d);
149*206fef1cSDavid du Colombier }
150*206fef1cSDavid du Colombier 
151*206fef1cSDavid du Colombier /*
152*206fef1cSDavid du Colombier  *  allocate a block from a bit vector page
153*206fef1cSDavid du Colombier  *
154*206fef1cSDavid du Colombier  *  a return value of Notabno means no blocks left
155*206fef1cSDavid du Colombier  */
156*206fef1cSDavid du Colombier static ulong
_balloc(Dalloc * ba,ulong max)157*206fef1cSDavid du Colombier _balloc(Dalloc *ba, ulong max)
158*206fef1cSDavid du Colombier {
159*206fef1cSDavid du Colombier 	int len;	/* number of valid words */
160*206fef1cSDavid du Colombier 	ulong i;	/* bit position in long */
161*206fef1cSDavid du Colombier 	ulong m;	/* 1<<i */
162*206fef1cSDavid du Colombier 	ulong v;	/* old value of long */
163*206fef1cSDavid du Colombier 	ulong *p, *e;
164*206fef1cSDavid du Colombier 
165*206fef1cSDavid du Colombier 	/*
166*206fef1cSDavid du Colombier 	 *  find a word with a 0 bit
167*206fef1cSDavid du Colombier 	 */
168*206fef1cSDavid du Colombier 	len = (max+BtoUL-1)/BtoUL;
169*206fef1cSDavid du Colombier 	for(p = ba->bits, e = p + len; p < e; p++)
170*206fef1cSDavid du Colombier 		if(*p != 0xFFFFFFFF)
171*206fef1cSDavid du Colombier 			break;
172*206fef1cSDavid du Colombier 	if(p == e)
173*206fef1cSDavid du Colombier 		return Notabno;
174*206fef1cSDavid du Colombier 
175*206fef1cSDavid du Colombier 	/*
176*206fef1cSDavid du Colombier 	 *  find the first 0 bit
177*206fef1cSDavid du Colombier 	 */
178*206fef1cSDavid du Colombier 	v = *p;
179*206fef1cSDavid du Colombier 	for(m = 1, i = 0; i < BtoUL; i++, m <<= 1)
180*206fef1cSDavid du Colombier 		if((m|v) != v)
181*206fef1cSDavid du Colombier 			break;
182*206fef1cSDavid du Colombier 
183*206fef1cSDavid du Colombier 	/*
184*206fef1cSDavid du Colombier 	 *  calculate block number
185*206fef1cSDavid du Colombier 	 */
186*206fef1cSDavid du Colombier 	i += (p - ba->bits)*BtoUL;
187*206fef1cSDavid du Colombier 	if(i >= max)
188*206fef1cSDavid du Colombier 		return Notabno;
189*206fef1cSDavid du Colombier 
190*206fef1cSDavid du Colombier 	/*
191*206fef1cSDavid du Colombier 	 *  set bit to 1
192*206fef1cSDavid du Colombier 	 */
193*206fef1cSDavid du Colombier 	*p = v | m;
194*206fef1cSDavid du Colombier 	return i;
195*206fef1cSDavid du Colombier }
196*206fef1cSDavid du Colombier 
197*206fef1cSDavid du Colombier /*
198*206fef1cSDavid du Colombier  *  allocate a block
199*206fef1cSDavid du Colombier  *
200*206fef1cSDavid du Colombier  *  return Notabno if none left
201*206fef1cSDavid du Colombier  */
202*206fef1cSDavid du Colombier ulong
dalloc(Disk * d,Dptr * p)203*206fef1cSDavid du Colombier dalloc(Disk *d, Dptr *p)
204*206fef1cSDavid du Colombier {
205*206fef1cSDavid du Colombier 	ulong	bno, max, rv;
206*206fef1cSDavid du Colombier 	Bbuf	*b;
207*206fef1cSDavid du Colombier 	Dalloc	*ba;
208*206fef1cSDavid du Colombier 
209*206fef1cSDavid du Colombier 	max = d->nb;
210*206fef1cSDavid du Colombier 	for(bno = 0; bno < d->nab; bno++){
211*206fef1cSDavid du Colombier 		b = bcread(d, bno);
212*206fef1cSDavid du Colombier 		ba = (Dalloc*)b->data;
213*206fef1cSDavid du Colombier 		rv = _balloc(ba, max > d->b2b ? d->b2b : max);
214*206fef1cSDavid du Colombier 		if(rv != Notabno){
215*206fef1cSDavid du Colombier 			rv = bno*d->b2b + rv;
216*206fef1cSDavid du Colombier 			if(p){
217*206fef1cSDavid du Colombier 				p->start = p->end = 0;
218*206fef1cSDavid du Colombier 				p->bno = rv;
219*206fef1cSDavid du Colombier 			}
220*206fef1cSDavid du Colombier 			bcmark(d, b);
221*206fef1cSDavid du Colombier 			return rv;
222*206fef1cSDavid du Colombier 		}
223*206fef1cSDavid du Colombier 		max -= d->b2b;
224*206fef1cSDavid du Colombier 	}
225*206fef1cSDavid du Colombier 	if(p)
226*206fef1cSDavid du Colombier 		p->bno = Notabno;
227*206fef1cSDavid du Colombier 	return Notabno;
228*206fef1cSDavid du Colombier }
229*206fef1cSDavid du Colombier 
230*206fef1cSDavid du Colombier /*
231*206fef1cSDavid du Colombier  *  allocate a block of pointers
232*206fef1cSDavid du Colombier  */
233*206fef1cSDavid du Colombier ulong
dpalloc(Disk * d,Dptr * p)234*206fef1cSDavid du Colombier dpalloc(Disk *d, Dptr *p)
235*206fef1cSDavid du Colombier {
236*206fef1cSDavid du Colombier 	Bbuf *b;
237*206fef1cSDavid du Colombier 	Dptr *sp, *ep;
238*206fef1cSDavid du Colombier 
239*206fef1cSDavid du Colombier 	if(dalloc(d, p) == Notabno)
240*206fef1cSDavid du Colombier 		return Notabno;
241*206fef1cSDavid du Colombier 
242*206fef1cSDavid du Colombier 	/*
243*206fef1cSDavid du Colombier 	 *  allocate the page and invalidate all the
244*206fef1cSDavid du Colombier 	 *  pointers
245*206fef1cSDavid du Colombier 	 */
246*206fef1cSDavid du Colombier 	b = bcalloc(d, p->bno);
247*206fef1cSDavid du Colombier 	if(b == 0)
248*206fef1cSDavid du Colombier 		return -1;
249*206fef1cSDavid du Colombier 	sp = (Dptr*)b->data;
250*206fef1cSDavid du Colombier 	for(ep = sp + d->p2b; sp < ep; sp++){
251*206fef1cSDavid du Colombier 		sp->bno = Notabno;
252*206fef1cSDavid du Colombier 		sp->start = sp->end = 0;
253*206fef1cSDavid du Colombier 	}
254*206fef1cSDavid du Colombier 	p->bno |= Indbno;
255*206fef1cSDavid du Colombier 	p->start = 0;
256*206fef1cSDavid du Colombier 	p->end = d->bsize;
257*206fef1cSDavid du Colombier 
258*206fef1cSDavid du Colombier 	/*
259*206fef1cSDavid du Colombier 	 *  mark the page as dirty
260*206fef1cSDavid du Colombier 	 */
261*206fef1cSDavid du Colombier 	bcmark(d, b);
262*206fef1cSDavid du Colombier 	return 0;
263*206fef1cSDavid du Colombier }
264*206fef1cSDavid du Colombier 
265*206fef1cSDavid du Colombier /*
266*206fef1cSDavid du Colombier  *  free a block
267*206fef1cSDavid du Colombier  */
268*206fef1cSDavid du Colombier int
_bfree(Disk * d,ulong i)269*206fef1cSDavid du Colombier _bfree(Disk *d, ulong i)
270*206fef1cSDavid du Colombier {
271*206fef1cSDavid du Colombier 	ulong bno, m;
272*206fef1cSDavid du Colombier 	ulong *p;
273*206fef1cSDavid du Colombier 	Bbuf *b;
274*206fef1cSDavid du Colombier 	Dalloc *ba;
275*206fef1cSDavid du Colombier 
276*206fef1cSDavid du Colombier 	/*
277*206fef1cSDavid du Colombier 	 *  get correct allocation block
278*206fef1cSDavid du Colombier 	 */
279*206fef1cSDavid du Colombier 	bno = i/d->b2b;
280*206fef1cSDavid du Colombier 	if(bno >= d->nab)
281*206fef1cSDavid du Colombier 		return -1;
282*206fef1cSDavid du Colombier 	b = bcread(d, bno);
283*206fef1cSDavid du Colombier 	if(b == 0)
284*206fef1cSDavid du Colombier 		return -1;
285*206fef1cSDavid du Colombier 	ba = (Dalloc*)b->data;
286*206fef1cSDavid du Colombier 
287*206fef1cSDavid du Colombier 	/*
288*206fef1cSDavid du Colombier 	 *  change bit
289*206fef1cSDavid du Colombier 	 */
290*206fef1cSDavid du Colombier 	i -= bno*d->b2b;
291*206fef1cSDavid du Colombier 	p = ba->bits + (i/BtoUL);
292*206fef1cSDavid du Colombier 	m = 1<<(i%BtoUL);
293*206fef1cSDavid du Colombier 	*p &= ~m;
294*206fef1cSDavid du Colombier 	bcmark(d, b);
295*206fef1cSDavid du Colombier 
296*206fef1cSDavid du Colombier 	return 0;
297*206fef1cSDavid du Colombier }
298*206fef1cSDavid du Colombier 
299*206fef1cSDavid du Colombier /*
300*206fef1cSDavid du Colombier  *  free a block (or blocks)
301*206fef1cSDavid du Colombier  */
302*206fef1cSDavid du Colombier int
dfree(Disk * d,Dptr * dp)303*206fef1cSDavid du Colombier dfree(Disk *d, Dptr *dp)
304*206fef1cSDavid du Colombier {
305*206fef1cSDavid du Colombier 	ulong bno;
306*206fef1cSDavid du Colombier 	Dptr *sp, *ep;
307*206fef1cSDavid du Colombier 	Bbuf *b;
308*206fef1cSDavid du Colombier 
309*206fef1cSDavid du Colombier 	bno = dp->bno;
310*206fef1cSDavid du Colombier 	dp->bno = Notabno;
311*206fef1cSDavid du Colombier 
312*206fef1cSDavid du Colombier 	/*
313*206fef1cSDavid du Colombier 	 *  nothing to free
314*206fef1cSDavid du Colombier 	 */
315*206fef1cSDavid du Colombier 	if(bno == Notabno)
316*206fef1cSDavid du Colombier 		return 0;
317*206fef1cSDavid du Colombier 
318*206fef1cSDavid du Colombier 	/*
319*206fef1cSDavid du Colombier 	 *  direct pointer
320*206fef1cSDavid du Colombier 	 */
321*206fef1cSDavid du Colombier 	if((bno & Indbno) == 0)
322*206fef1cSDavid du Colombier 		return _bfree(d, bno);
323*206fef1cSDavid du Colombier 
324*206fef1cSDavid du Colombier 	/*
325*206fef1cSDavid du Colombier 	 *  first indirect page
326*206fef1cSDavid du Colombier 	 */
327*206fef1cSDavid du Colombier 	bno &= ~Indbno;
328*206fef1cSDavid du Colombier 	_bfree(d, bno);
329*206fef1cSDavid du Colombier 
330*206fef1cSDavid du Colombier 	/*
331*206fef1cSDavid du Colombier 	 *  then all the pages it points to
332*206fef1cSDavid du Colombier 	 *
333*206fef1cSDavid du Colombier 	 *	DANGER: this algorithm may fail if there are more
334*206fef1cSDavid du Colombier 	 *		allocation blocks than block buffers
335*206fef1cSDavid du Colombier 	 */
336*206fef1cSDavid du Colombier 	b = bcread(d, bno);
337*206fef1cSDavid du Colombier 	if(b == 0)
338*206fef1cSDavid du Colombier 		return -1;
339*206fef1cSDavid du Colombier 	sp = (Dptr*)b->data;
340*206fef1cSDavid du Colombier 	for(ep = sp + d->p2b; sp < ep; sp++)
341*206fef1cSDavid du Colombier 		if(dfree(d, sp) < 0)
342*206fef1cSDavid du Colombier 			return -1;
343*206fef1cSDavid du Colombier 	return 0;
344*206fef1cSDavid du Colombier }
345