xref: /plan9-contrib/sys/src/cmd/ramcfs/file.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 #include "inode.h"
8*206fef1cSDavid du Colombier #include "file.h"
9*206fef1cSDavid du Colombier 
10*206fef1cSDavid du Colombier /*
11*206fef1cSDavid du Colombier  *  merge data with that which already exists in a block
12*206fef1cSDavid du Colombier  *
13*206fef1cSDavid du Colombier  *  we allow only one range per block, always use the new
14*206fef1cSDavid du Colombier  *  data if the ranges don't overlap.
15*206fef1cSDavid du Colombier  */
16*206fef1cSDavid du Colombier void
fmerge(Dptr * p,char * to,char * from,int start,int len)17*206fef1cSDavid du Colombier fmerge(Dptr *p, char *to, char *from, int start, int len)
18*206fef1cSDavid du Colombier {
19*206fef1cSDavid du Colombier 	int end;
20*206fef1cSDavid du Colombier 
21*206fef1cSDavid du Colombier 	end = start + len;
22*206fef1cSDavid du Colombier 	memmove(to+start, from, end-start);
23*206fef1cSDavid du Colombier 
24*206fef1cSDavid du Colombier 	/*
25*206fef1cSDavid du Colombier 	 *  if ranges do not overlap...
26*206fef1cSDavid du Colombier 	 */
27*206fef1cSDavid du Colombier 	if(start>p->end || p->start>end){
28*206fef1cSDavid du Colombier 		/*
29*206fef1cSDavid du Colombier 		 *  just use the new data
30*206fef1cSDavid du Colombier 		 */
31*206fef1cSDavid du Colombier 		p->start = start;
32*206fef1cSDavid du Colombier 		p->end = end;
33*206fef1cSDavid du Colombier 	} else {
34*206fef1cSDavid du Colombier 		/*
35*206fef1cSDavid du Colombier 		 *  merge ranges
36*206fef1cSDavid du Colombier 		 */
37*206fef1cSDavid du Colombier 		if(start < p->start)
38*206fef1cSDavid du Colombier 			p->start = start;
39*206fef1cSDavid du Colombier 		if(end > p->end)
40*206fef1cSDavid du Colombier 			p->end = end;
41*206fef1cSDavid du Colombier 	}
42*206fef1cSDavid du Colombier 
43*206fef1cSDavid du Colombier }
44*206fef1cSDavid du Colombier 
45*206fef1cSDavid du Colombier /*
46*206fef1cSDavid du Colombier  *  write a block (or less) of data onto a disk, follow it with any necessary
47*206fef1cSDavid du Colombier  *  pointer writes.
48*206fef1cSDavid du Colombier  *
49*206fef1cSDavid du Colombier  *	N.B. ordering is everything
50*206fef1cSDavid du Colombier  */
51*206fef1cSDavid du Colombier int
fbwrite(Icache * ic,Ibuf * b,char * a,ulong off,int len)52*206fef1cSDavid du Colombier fbwrite(Icache *ic, Ibuf *b, char *a, ulong off, int len)
53*206fef1cSDavid du Colombier {
54*206fef1cSDavid du Colombier 	int wrinode;
55*206fef1cSDavid du Colombier 	ulong fbno;
56*206fef1cSDavid du Colombier 	Bbuf *dbb;	/* data block */
57*206fef1cSDavid du Colombier 	Bbuf *ibb;	/* indirect block */
58*206fef1cSDavid du Colombier 	Dptr *p;
59*206fef1cSDavid du Colombier 	Dptr t;
60*206fef1cSDavid du Colombier 
61*206fef1cSDavid du Colombier 	fbno = off / ic->bsize;
62*206fef1cSDavid du Colombier 	p = &b->inode.ptr;
63*206fef1cSDavid du Colombier 	ibb = 0;
64*206fef1cSDavid du Colombier 	wrinode = 0;
65*206fef1cSDavid du Colombier 
66*206fef1cSDavid du Colombier 	/*
67*206fef1cSDavid du Colombier 	 *  are there any pages for this inode?
68*206fef1cSDavid du Colombier 	 */
69*206fef1cSDavid du Colombier 	if(p->bno == Notabno){
70*206fef1cSDavid du Colombier 		wrinode = 1;
71*206fef1cSDavid du Colombier 		goto dowrite;
72*206fef1cSDavid du Colombier 	}
73*206fef1cSDavid du Colombier 
74*206fef1cSDavid du Colombier 	/*
75*206fef1cSDavid du Colombier  	 *  is it an indirect block?
76*206fef1cSDavid du Colombier 	 */
77*206fef1cSDavid du Colombier 	if(p->bno & Indbno){
78*206fef1cSDavid du Colombier 		ibb = bcread(ic, p->bno);
79*206fef1cSDavid du Colombier 		if(ibb == 0)
80*206fef1cSDavid du Colombier 			return -1;
81*206fef1cSDavid du Colombier 		p = (Dptr*)ibb->data;
82*206fef1cSDavid du Colombier 		p += fbno % ic->p2b;
83*206fef1cSDavid du Colombier 		goto dowrite;
84*206fef1cSDavid du Colombier 	}
85*206fef1cSDavid du Colombier 
86*206fef1cSDavid du Colombier 	/*
87*206fef1cSDavid du Colombier  	 *  is it the wrong direct block?
88*206fef1cSDavid du Colombier 	 */
89*206fef1cSDavid du Colombier 	if((p->fbno%ic->p2b) != (fbno%ic->p2b)){
90*206fef1cSDavid du Colombier 		/*
91*206fef1cSDavid du Colombier 		 *  yes, make an indirect block
92*206fef1cSDavid du Colombier 		 */
93*206fef1cSDavid du Colombier 		t = *p;
94*206fef1cSDavid du Colombier 		dpalloc(ic, p);
95*206fef1cSDavid du Colombier 		if(p->bno == Notabno){
96*206fef1cSDavid du Colombier 			*p = t;
97*206fef1cSDavid du Colombier 			return -1;
98*206fef1cSDavid du Colombier 		}
99*206fef1cSDavid du Colombier 		ibb = bcalloc(ic, p->bno);
100*206fef1cSDavid du Colombier 		if(ibb == 0){
101*206fef1cSDavid du Colombier 			*p = t;
102*206fef1cSDavid du Colombier 			return -1;
103*206fef1cSDavid du Colombier 		}
104*206fef1cSDavid du Colombier 		p = (Dptr*)ibb->data;
105*206fef1cSDavid du Colombier 		p += t.fbno % ic->p2b;
106*206fef1cSDavid du Colombier 		*p = t;
107*206fef1cSDavid du Colombier 		p = (Dptr*)ibb->data;
108*206fef1cSDavid du Colombier 		p += fbno % ic->p2b;
109*206fef1cSDavid du Colombier 	}
110*206fef1cSDavid du Colombier 	wrinode = 1;
111*206fef1cSDavid du Colombier 
112*206fef1cSDavid du Colombier dowrite:
113*206fef1cSDavid du Colombier 	/*
114*206fef1cSDavid du Colombier 	 *  get the data block into the block cache
115*206fef1cSDavid du Colombier 	 */
116*206fef1cSDavid du Colombier 	if(p->bno == Notabno){
117*206fef1cSDavid du Colombier 		/*
118*206fef1cSDavid du Colombier 		 *  create a new block
119*206fef1cSDavid du Colombier 		 */
120*206fef1cSDavid du Colombier 		dalloc(ic, p);
121*206fef1cSDavid du Colombier 		if(p->bno == Notabno)
122*206fef1cSDavid du Colombier 			return -1;		/* no blocks left (maybe) */
123*206fef1cSDavid du Colombier 		dbb = bcalloc(ic, p->bno);
124*206fef1cSDavid du Colombier 	} else {
125*206fef1cSDavid du Colombier 		/*
126*206fef1cSDavid du Colombier 		 *  use what's there
127*206fef1cSDavid du Colombier 		 */
128*206fef1cSDavid du Colombier 		dbb = bcread(ic, p->bno);
129*206fef1cSDavid du Colombier 	}
130*206fef1cSDavid du Colombier 	if(dbb == 0)
131*206fef1cSDavid du Colombier 		return -1;
132*206fef1cSDavid du Colombier 
133*206fef1cSDavid du Colombier 	/*
134*206fef1cSDavid du Colombier 	 *  merge in the new data
135*206fef1cSDavid du Colombier 	 */
136*206fef1cSDavid du Colombier 	if(p->fbno != fbno){
137*206fef1cSDavid du Colombier 		p->start = p->end = 0;
138*206fef1cSDavid du Colombier 		p->fbno = fbno;
139*206fef1cSDavid du Colombier 	}
140*206fef1cSDavid du Colombier 	fmerge(p, dbb->data, a, off % ic->bsize, len);
141*206fef1cSDavid du Colombier 
142*206fef1cSDavid du Colombier 	/*
143*206fef1cSDavid du Colombier 	 *  write changed blocks back in the
144*206fef1cSDavid du Colombier 	 *  correct order
145*206fef1cSDavid du Colombier 	 */
146*206fef1cSDavid du Colombier 	bcmark(ic, dbb);
147*206fef1cSDavid du Colombier 	if(ibb)
148*206fef1cSDavid du Colombier 		bcmark(ic, ibb);
149*206fef1cSDavid du Colombier 	if(wrinode)
150*206fef1cSDavid du Colombier 		if(iwrite(ic, b) < 0)
151*206fef1cSDavid du Colombier 			return -1;
152*206fef1cSDavid du Colombier 	return len;
153*206fef1cSDavid du Colombier }
154*206fef1cSDavid du Colombier 
155*206fef1cSDavid du Colombier /*
156*206fef1cSDavid du Colombier  *  write `n' bytes to the cache
157*206fef1cSDavid du Colombier  *
158*206fef1cSDavid du Colombier  *  return number of bytes written
159*206fef1cSDavid du Colombier  */
160*206fef1cSDavid du Colombier long
fwrite(Icache * ic,Ibuf * b,char * a,ulong off,long n)161*206fef1cSDavid du Colombier fwrite(Icache *ic, Ibuf *b, char *a, ulong off, long n)
162*206fef1cSDavid du Colombier {
163*206fef1cSDavid du Colombier 	int len;
164*206fef1cSDavid du Colombier 	long sofar;
165*206fef1cSDavid du Colombier 
166*206fef1cSDavid du Colombier 	for(sofar = 0; sofar < n; sofar += len){
167*206fef1cSDavid du Colombier 		len = ic->bsize - ((off+sofar)%ic->bsize);
168*206fef1cSDavid du Colombier 		if(len > n - sofar)
169*206fef1cSDavid du Colombier 			len = n - sofar;
170*206fef1cSDavid du Colombier 		if(fbwrite(ic, b, a+sofar, off+sofar, len) < 0)
171*206fef1cSDavid du Colombier 			return sofar;
172*206fef1cSDavid du Colombier 	}
173*206fef1cSDavid du Colombier 	return sofar;
174*206fef1cSDavid du Colombier }
175*206fef1cSDavid du Colombier 
176*206fef1cSDavid du Colombier /*
177*206fef1cSDavid du Colombier  *  get a pointer to the next valid data at or after `off'
178*206fef1cSDavid du Colombier  */
179*206fef1cSDavid du Colombier Dptr *
fpget(Icache * ic,Ibuf * b,ulong off)180*206fef1cSDavid du Colombier fpget(Icache *ic, Ibuf *b, ulong off)
181*206fef1cSDavid du Colombier {
182*206fef1cSDavid du Colombier 	ulong fbno;
183*206fef1cSDavid du Colombier 	long doff;
184*206fef1cSDavid du Colombier 	Bbuf *ibb;	/* indirect block */
185*206fef1cSDavid du Colombier 	Dptr *p, *p0, *pf;
186*206fef1cSDavid du Colombier 
187*206fef1cSDavid du Colombier 	fbno = off / ic->bsize;
188*206fef1cSDavid du Colombier 	p = &b->inode.ptr;
189*206fef1cSDavid du Colombier 
190*206fef1cSDavid du Colombier 	/*
191*206fef1cSDavid du Colombier 	 *  are there any pages for this inode?
192*206fef1cSDavid du Colombier 	 */
193*206fef1cSDavid du Colombier 	if(p->bno == Notabno)
194*206fef1cSDavid du Colombier 		return 0;
195*206fef1cSDavid du Colombier 
196*206fef1cSDavid du Colombier 	/*
197*206fef1cSDavid du Colombier  	 *  if it's a direct block, life is easy?
198*206fef1cSDavid du Colombier 	 */
199*206fef1cSDavid du Colombier 	if(!(p->bno & Indbno)){
200*206fef1cSDavid du Colombier 		/*
201*206fef1cSDavid du Colombier 		 *  a direct block, return p if it's at least past what we want
202*206fef1cSDavid du Colombier 		 */
203*206fef1cSDavid du Colombier 		if(p->fbno > fbno)
204*206fef1cSDavid du Colombier 			return p;
205*206fef1cSDavid du Colombier 		if(p->fbno < fbno)
206*206fef1cSDavid du Colombier 			return 0;
207*206fef1cSDavid du Colombier 		doff = off % ic->bsize;
208*206fef1cSDavid du Colombier 		if(doff>=p->start && doff<p->end)
209*206fef1cSDavid du Colombier 			return p;
210*206fef1cSDavid du Colombier 		else
211*206fef1cSDavid du Colombier 			return 0;
212*206fef1cSDavid du Colombier 	}
213*206fef1cSDavid du Colombier 
214*206fef1cSDavid du Colombier 	/*
215*206fef1cSDavid du Colombier 	 *  read the indirect block
216*206fef1cSDavid du Colombier 	 */
217*206fef1cSDavid du Colombier 	ibb = bcread(ic, p->bno);
218*206fef1cSDavid du Colombier 	if(ibb == 0)
219*206fef1cSDavid du Colombier 		return 0;
220*206fef1cSDavid du Colombier 
221*206fef1cSDavid du Colombier 	/*
222*206fef1cSDavid du Colombier 	 *  find the next valid pointer
223*206fef1cSDavid du Colombier 	 */
224*206fef1cSDavid du Colombier 	p0 = (Dptr*)ibb->data;
225*206fef1cSDavid du Colombier 	pf = p0 + (fbno % ic->p2b);
226*206fef1cSDavid du Colombier 	if(pf->bno!=Notabno && pf->fbno==fbno){
227*206fef1cSDavid du Colombier 		doff = off % ic->bsize;
228*206fef1cSDavid du Colombier 		if(doff<pf->end)
229*206fef1cSDavid du Colombier 			return pf;
230*206fef1cSDavid du Colombier 	}
231*206fef1cSDavid du Colombier 	for(p = pf+1; p < p0 + ic->p2b; p++){
232*206fef1cSDavid du Colombier 		fbno++;
233*206fef1cSDavid du Colombier 		if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end)
234*206fef1cSDavid du Colombier 			return p;
235*206fef1cSDavid du Colombier 	}
236*206fef1cSDavid du Colombier 	for(p = p0; p < pf; p++){
237*206fef1cSDavid du Colombier 		fbno++;
238*206fef1cSDavid du Colombier 		if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end)
239*206fef1cSDavid du Colombier 			return p;
240*206fef1cSDavid du Colombier 	}
241*206fef1cSDavid du Colombier 	return 0;
242*206fef1cSDavid du Colombier }
243*206fef1cSDavid du Colombier 
244*206fef1cSDavid du Colombier /*
245*206fef1cSDavid du Colombier  *  read `n' bytes from the cache.
246*206fef1cSDavid du Colombier  *
247*206fef1cSDavid du Colombier  *  if we hit a gap and we've read something,
248*206fef1cSDavid du Colombier  *  return number of bytes read so far.
249*206fef1cSDavid du Colombier  *
250*206fef1cSDavid du Colombier  *  if we start with a gap, return minus the number of bytes
251*206fef1cSDavid du Colombier  *  to the next data.
252*206fef1cSDavid du Colombier  *
253*206fef1cSDavid du Colombier  *  if there are no bytes cached, return 0.
254*206fef1cSDavid du Colombier  */
255*206fef1cSDavid du Colombier long
fread(Icache * ic,Ibuf * b,char * a,ulong off,long n)256*206fef1cSDavid du Colombier fread(Icache *ic, Ibuf *b, char *a, ulong off, long n)
257*206fef1cSDavid du Colombier {
258*206fef1cSDavid du Colombier 	int len, start;
259*206fef1cSDavid du Colombier 	long sofar, gap;
260*206fef1cSDavid du Colombier 	Dptr *p;
261*206fef1cSDavid du Colombier 	Bbuf *bb;
262*206fef1cSDavid du Colombier 
263*206fef1cSDavid du Colombier 	for(sofar = 0; sofar < n; sofar += len, off += len){
264*206fef1cSDavid du Colombier 		/*
265*206fef1cSDavid du Colombier 		 *  get pointer to next data
266*206fef1cSDavid du Colombier 		 */
267*206fef1cSDavid du Colombier 		len = n - sofar;
268*206fef1cSDavid du Colombier 		p = fpget(ic, b, off);
269*206fef1cSDavid du Colombier 
270*206fef1cSDavid du Colombier 		/*
271*206fef1cSDavid du Colombier 		 *  if no more data, return what we have so far
272*206fef1cSDavid du Colombier 		 */
273*206fef1cSDavid du Colombier 		if(p == 0)
274*206fef1cSDavid du Colombier 			return sofar;
275*206fef1cSDavid du Colombier 
276*206fef1cSDavid du Colombier 		/*
277*206fef1cSDavid du Colombier 		 *  if there's a gap, return the size of the gap
278*206fef1cSDavid du Colombier 		 */
279*206fef1cSDavid du Colombier 		gap = (ic->bsize*p->fbno + p->start) - off;
280*206fef1cSDavid du Colombier 		if(gap>0)
281*206fef1cSDavid du Colombier 			if(sofar == 0)
282*206fef1cSDavid du Colombier 				return -gap;
283*206fef1cSDavid du Colombier 			else
284*206fef1cSDavid du Colombier 				return sofar;
285*206fef1cSDavid du Colombier 
286*206fef1cSDavid du Colombier 		/*
287*206fef1cSDavid du Colombier 		 *  return what we have
288*206fef1cSDavid du Colombier 		 */
289*206fef1cSDavid du Colombier 		bb = bcread(ic, p->bno);
290*206fef1cSDavid du Colombier 		if(bb == 0)
291*206fef1cSDavid du Colombier 			return sofar;
292*206fef1cSDavid du Colombier 		start = p->start - gap;
293*206fef1cSDavid du Colombier 		if(p->end - start < len)
294*206fef1cSDavid du Colombier 			len = p->end - start;
295*206fef1cSDavid du Colombier 		memmove(a + sofar, bb->data + start, len);
296*206fef1cSDavid du Colombier 	}
297*206fef1cSDavid du Colombier 	return sofar;
298*206fef1cSDavid du Colombier }
299