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