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 "all.h"
2
 
3
Dentry*
4
getdir(Iobuf *p, int slot)
5
{
6
	if(!p)
7
		return 0;
8
	return (Dentry*)p->iobuf + slot%DIRPERBUF;
9
}
10
 
11
void
12
accessdir(Iobuf *p, Dentry *d, int f, int uid)
13
{
14
	Timet t;
15
 
16
	if(p && p->dev->type != Devro) {
17
		p->flags |= Bmod;
18
		t = time(nil);
19
		if(f & (FREAD|FWRITE))
20
			d->atime = t;
21
		if(f & FWRITE) {
22
			d->mtime = t;
23
			d->muid = uid;
24
			d->qid.version++;
25
		}
26
	}
27
}
28
 
29
void
30
preread(Device *d, Off addr)
31
{
32
	Rabuf *rb;
33
 
34
	if(addr == 0)
35
		return;
36
	if(raheadq->count+10 >= raheadq->size)	/* ugly knowing layout */
37
		return;
38
	lock(&rabuflock);
39
	rb = rabuffree;
40
	if(rb == 0) {
41
		unlock(&rabuflock);
42
		return;
43
	}
44
	rabuffree = rb->link;
45
	unlock(&rabuflock);
46
	rb->dev = d;
47
	rb->addr = addr;
48
	fs_send(raheadq, rb);
49
}
50
 
51
Off
52
rel2abs(Iobuf *p, Dentry *d, Off a, int tag, int putb, int uid)
53
{
54
	int i;
55
	Off addr, qpath, indaddrs = 1, div;
56
	Device *dev;
57
 
58
	if(a < 0) {
59
		print("rel2abs: neg offset\n");
60
		if(putb)
61
			putbuf(p);
62
		return 0;
63
	}
64
	dev = p->dev;
65
	qpath = d->qid.path;
66
 
67
	/* is `a' a direct block? */
68
	if(a < NDBLOCK) {
69
		addr = d->dblock[a];
70
		if(!addr && tag) {
71
			addr = bufalloc(dev, tag, qpath, uid);
72
			d->dblock[a] = addr;
73
			p->flags |= Bmod|Bimm;
74
		}
75
		if(putb)
76
			putbuf(p);
77
		return addr;
78
	}
79
	a -= NDBLOCK;
80
 
81
	/*
82
	 * loop through indirect block depths.
83
	 */
84
	for (i = 0; i < NIBLOCK; i++) {
85
		indaddrs *= INDPERBUF;
86
		/* is a's disk addr in this indir block or one of its kids? */
87
		if (a < indaddrs) {
88
			addr = d->iblocks[i];
89
			if(!addr && tag) {
90
				addr = bufalloc(dev, Tind1+i, qpath, uid);
91
				d->iblocks[i] = addr;
92
				p->flags |= Bmod|Bimm;
93
			}
94
			if(putb)
95
				putbuf(p);
96
 
97
			div = indaddrs;
98
			for (; i >= 0; i--) {
99
				div /= INDPERBUF;
100
				if (div <= 0)
101
					panic("rel2abs: non-positive divisor");
102
				addr = indfetch(dev, qpath, addr,
103
					(a/div)%INDPERBUF, Tind1+i,
104
					(i == 0? tag: Tind1+i-1), uid);
105
			}
106
			return addr;
107
		}
108
		a -= indaddrs;
109
	}
110
	if(putb)
111
		putbuf(p);
112
 
113
	/* quintuple-indirect blocks not implemented. */
114
	print("rel2abs: no %d-deep indirect\n", NIBLOCK+1);
115
	return 0;
116
}
117
 
118
/*
119
 * read-ahead strategy
120
 * on second block, read RAGAP blocks,
121
 * thereafter, read RAGAP ahead of current pos
122
 */
123
Off
124
dbufread(Iobuf *p, Dentry *d, Off a, Off ra, int uid)
125
{
126
	Off addr;
127
 
128
	if(a == 0)
129
		return 1;
130
	if(a == 1 && ra == 1) {
131
		while(ra < a+RAGAP) {
132
			ra++;
133
			addr = rel2abs(p, d, ra, 0, 0, uid);
134
			if(!addr)
135
				return 0;
136
			preread(p->dev, addr);
137
		}
138
		return ra+1;
139
	}
140
	if(ra == a+RAGAP) {
141
		addr = rel2abs(p, d, ra, 0, 0, uid);
142
		if(!addr)
143
			return 0;
144
		preread(p->dev, addr);
145
		return ra+1;
146
	}
147
	return ra;
148
}
149
 
150
Iobuf*
151
dnodebuf(Iobuf *p, Dentry *d, Off a, int tag, int uid)
152
{
153
	Off addr;
154
 
155
	addr = rel2abs(p, d, a, tag, 0, uid);
156
	if(addr)
157
		return getbuf(p->dev, addr, Brd);
158
	return 0;
159
}
160
 
161
/*
162
 * same as dnodebuf but it calls putbuf(p)
163
 * to reduce interference.
164
 */
165
Iobuf*
166
dnodebuf1(Iobuf *p, Dentry *d, Off a, int tag, int uid)
167
{
168
	Off addr;
169
	Device *dev;
170
 
171
	dev = p->dev;
172
	addr = rel2abs(p, d, a, tag, 1, uid);
173
	if(addr)
174
		return getbuf(dev, addr, Brd);
175
	return 0;
176
 
177
}
178
 
179
Off
180
indfetch(Device* d, Off qpath, Off addr, Off a, int itag, int tag, int uid)
181
{
182
	Iobuf *bp;
183
 
184
	if(!addr)
185
		return 0;
186
	bp = getbuf(d, addr, Brd);
187
	if(!bp || checktag(bp, itag, qpath)) {
188
		if(!bp) {
189
			print("ind fetch bp = 0\n");
190
			return 0;
191
		}
192
		print("ind fetch tag\n");
193
		putbuf(bp);
194
		return 0;
195
	}
196
	addr = ((Off *)bp->iobuf)[a];
197
	if(!addr && tag) {
198
		addr = bufalloc(d, tag, qpath, uid);
199
		if(addr) {
200
			((Off *)bp->iobuf)[a] = addr;
201
			bp->flags |= Bmod;
202
			if(tag == Tdir)
203
				bp->flags |= Bimm;
204
			settag(bp, itag, qpath);
205
		}
206
	}
207
	putbuf(bp);
208
	return addr;
209
}
210
 
211
/* return INDPERBUF^exp */
212
Off
213
ibbpow(int exp)
214
{
215
	static Off pows[] = {
216
		1,
217
		INDPERBUF,
218
		(Off)INDPERBUF*INDPERBUF,
219
		(Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
220
		(Off)INDPERBUF*(Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
221
	};
222
 
223
	if (exp < 0)
224
		return 0;
225
	else if (exp >= nelem(pows)) {	/* not in table? do it long-hand */
226
		Off indpow = 1;
227
 
228
		while (exp-- > 0 && indpow > 0)
229
			indpow *= INDPERBUF;
230
		return indpow;
231
	} else
232
		return pows[exp];
233
}
234
 
235
/* return sum of INDPERBUF^n for 1 ≤ n ≤ exp */
236
Off
237
ibbpowsum(int exp)
238
{
239
	Off indsum = 0;
240
 
241
	for (; exp > 0; exp--)
242
		indsum += ibbpow(exp);
243
	return indsum;
244
}
245
 
246
/* zero bytes past new file length; return an error code */
247
int
248
trunczero(Truncstate *ts)
249
{
250
	int blkoff = ts->newsize % BUFSIZE;
251
	Iobuf *pd;
252
 
253
	pd = dnodebuf(ts->p, ts->d, ts->lastblk, Tfile, ts->uid);
254
	if (pd == nil || checktag(pd, Tfile, QPNONE)) {
255
		if (pd != nil)
256
			putbuf(pd);
257
		ts->err = Ephase;
258
		return Ephase;
259
	}
260
	memset(pd->iobuf+blkoff, 0, BUFSIZE - blkoff);
261
	putbuf(pd);
262
	return 0;
263
}
264
 
265
/*
266
 * truncate d (in p) to length `newsize'.
267
 * if larger, just increase size.
268
 * if smaller, deallocate blocks after last one
269
 * still in file at new size.  last byte to keep
270
 * is newsize-1, due to zero origin.
271
 * we free in forward order because it's simpler to get right.
272
 * if the final block at the new size is partially-filled,
273
 * zero the remainder.
274
 */
275
int
276
dtrunclen(Iobuf *p, Dentry *d, Off newsize, int uid)
277
{
278
	int i, pastlast;
279
	Truncstate trunc;
280
 
281
	if (newsize <= 0) {
282
		dtrunc(p, d, uid);
283
		return 0;
284
	}
285
	memset(&trunc, 0, sizeof trunc);
286
	trunc.d = d;
287
	trunc.p = p;
288
	trunc.uid = uid;
289
	trunc.newsize = newsize;
290
	trunc.lastblk = newsize/BUFSIZE;
291
	if (newsize % BUFSIZE == 0)
292
		trunc.lastblk--;
293
	else
294
		trunczero(&trunc);
295
	for (i = 0; i < NDBLOCK; i++)
296
		if (trunc.pastlast) {
297
			trunc.relblk = i;
298
			buffree(p->dev, d->dblock[i], 0, &trunc);
299
			d->dblock[i] = 0;
300
		} else if (i == trunc.lastblk)
301
			trunc.pastlast = 1;
302
	trunc.relblk = NDBLOCK;
303
	for (i = 0; i < NIBLOCK; i++) {
304
		pastlast = trunc.pastlast;
305
		buffree(p->dev, d->iblocks[i], i+1, &trunc);
306
		if (pastlast)
307
			d->iblocks[i] = 0;
308
	}
309
 
310
	d->size = newsize;
311
	p->flags |= Bmod|Bimm;
312
	accessdir(p, d, FWRITE, uid);
313
	return trunc.err;
314
}
315
 
316
/*
317
 * truncate d (in p) to zero length.
318
 * freeing blocks in reverse order is traditional, from Unix,
319
 * in an attempt to keep the free list contiguous.
320
 */
321
void
322
dtrunc(Iobuf *p, Dentry *d, int uid)
323
{
324
	int i;
325
 
326
	for (i = NIBLOCK-1; i >= 0; i--) {
327
		buffree(p->dev, d->iblocks[i], i+1, nil);
328
		d->iblocks[i] = 0;
329
	}
330
	for (i = NDBLOCK-1; i >= 0; i--) {
331
		buffree(p->dev, d->dblock[i], 0, nil);
332
		d->dblock[i] = 0;
333
	}
334
	d->size = 0;
335
	p->flags |= Bmod|Bimm;
336
	accessdir(p, d, FWRITE, uid);
337
}