Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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