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