4 getdir(Iobuf *p, int slot)
8 return (Dentry*)p->iobuf + slot%DIRPERBUF;
12 accessdir(Iobuf *p, Dentry *d, int f, int uid)
16 if(p == nil || p->dev->type == Devro)
19 if(f != FWRITE && noatime)
32 preread(Device *d, Off addr)
38 if(raheadq->count+10 >= raheadq->size) /* ugly knowing layout */
54 rel2abs(Iobuf *p, Dentry *d, Off a, int tag, int putb, int uid)
57 Off addr, qpath, indaddrs = 1, div;
61 fprint(2, "rel2abs: neg offset\n");
69 /* is `a' a direct block? */
73 addr = bufalloc(dev, tag, qpath, uid);
75 p->flags |= Bmod|Bimm;
84 * loop through indirect block depths.
86 for (i = 0; i < NIBLOCK; i++) {
87 indaddrs *= INDPERBUF;
88 /* is a's disk addr in this indir block or one of its kids? */
92 addr = bufalloc(dev, Tind1+i, qpath, uid);
94 p->flags |= Bmod|Bimm;
100 for (; i >= 0; i--) {
103 panic("rel2abs: non-positive divisor");
104 addr = indfetch(dev, qpath, addr,
105 (a/div)%INDPERBUF, Tind1+i,
106 (i == 0? tag: Tind1+i-1), uid);
115 /* quintuple-indirect blocks not implemented. */
116 fprint(2, "rel2abs: no %d-deep indirect\n", NIBLOCK+1);
121 * read-ahead strategy
122 * on second block, read RAGAP blocks,
123 * thereafter, read RAGAP ahead of current pos
126 dbufread(Iobuf *p, Dentry *d, Off a, Off ra, int uid)
132 if(a == 1 && ra == 1) {
133 while(ra < a+RAGAP) {
135 addr = rel2abs(p, d, ra, 0, 0, uid);
138 preread(p->dev, addr);
143 addr = rel2abs(p, d, ra, 0, 0, uid);
146 preread(p->dev, addr);
153 dnodebuf(Iobuf *p, Dentry *d, Off a, int tag, int uid)
157 addr = rel2abs(p, d, a, tag, 0, uid);
159 return getbuf(p->dev, addr, Brd);
164 * same as dnodebuf but it calls putbuf(p)
165 * to reduce interference.
168 dnodebuf1(Iobuf *p, Dentry *d, Off a, int tag, int uid)
174 addr = rel2abs(p, d, a, tag, 1, uid);
176 return getbuf(dev, addr, Brd);
182 indfetch(Device* d, Off qpath, Off addr, Off a, int itag, int tag, int uid)
188 bp = getbuf(d, addr, Brd);
189 if(!bp || checktag(bp, itag, qpath)) {
191 fprint(2, "ind fetch bp = 0\n");
194 fprint(2, "ind fetch tag\n");
198 addr = ((Off *)bp->iobuf)[a];
200 addr = bufalloc(d, tag, qpath, uid);
202 ((Off *)bp->iobuf)[a] = addr;
206 settag(bp, itag, qpath);
213 /* return INDPERBUF^exp */
217 static Off pows[] = {
220 (Off)INDPERBUF*INDPERBUF,
221 (Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
222 (Off)INDPERBUF*(Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
227 else if (exp >= nelem(pows)) { /* not in table? do it long-hand */
230 while (exp-- > 0 && indpow > 0)
237 /* return sum of INDPERBUF^n for 1 ≤ n ≤ exp */
243 for (; exp > 0; exp--)
244 indsum += ibbpow(exp);
248 /* zero bytes past new file length; return an error code */
250 trunczero(Truncstate *ts)
252 int blkoff = ts->newsize % BUFSIZE;
255 pd = dnodebuf(ts->p, ts->d, ts->lastblk, Tfile, ts->uid);
256 if (pd == nil || checktag(pd, Tfile, QPNONE)) {
262 memset(pd->iobuf+blkoff, 0, BUFSIZE - blkoff);
268 * truncate d (in p) to length `newsize'.
269 * if larger, just increase size.
270 * if smaller, deallocate blocks after last one
271 * still in file at new size. last byte to keep
272 * is newsize-1, due to zero origin.
273 * we free in forward order because it's simpler to get right.
274 * if the final block at the new size is partially-filled,
275 * zero the remainder.
278 dtrunclen(Iobuf *p, Dentry *d, Off newsize, int uid)
287 memset(&trunc, 0, sizeof trunc);
291 trunc.newsize = newsize;
292 trunc.lastblk = newsize/BUFSIZE;
293 if (newsize % BUFSIZE == 0)
297 for (i = 0; i < NDBLOCK; i++)
298 if (trunc.pastlast) {
300 buffree(p->dev, d->dblock[i], 0, &trunc);
302 } else if (i == trunc.lastblk)
304 trunc.relblk = NDBLOCK;
305 for (i = 0; i < NIBLOCK; i++) {
306 pastlast = trunc.pastlast;
307 buffree(p->dev, d->iblocks[i], i+1, &trunc);
313 p->flags |= Bmod|Bimm;
314 accessdir(p, d, FWRITE, uid);
319 * truncate d (in p) to zero length.
320 * freeing blocks in reverse order is traditional, from Unix,
321 * in an attempt to keep the free list contiguous.
324 dtrunc(Iobuf *p, Dentry *d, int uid)
328 for (i = NIBLOCK-1; i >= 0; i--) {
329 buffree(p->dev, d->iblocks[i], i+1, nil);
332 for (i = NDBLOCK-1; i >= 0; i--) {
333 buffree(p->dev, d->dblock[i], 0, nil);
337 p->flags |= Bmod|Bimm;
338 accessdir(p, d, FWRITE, uid);