2 056fe1ba 2003-11-23 devnull * Manage tree of VtFiles stored in the block cache.
4 056fe1ba 2003-11-23 devnull * The single point of truth for the info about the VtFiles themselves
5 056fe1ba 2003-11-23 devnull * is the block data. Because of this, there is no explicit locking of
6 056fe1ba 2003-11-23 devnull * VtFile structures, and indeed there may be more than one VtFile
7 056fe1ba 2003-11-23 devnull * structure for a given Venti file. They synchronize through the
8 056fe1ba 2003-11-23 devnull * block cache.
10 056fe1ba 2003-11-23 devnull * This is a bit simpler than fossil because there are no epochs
11 056fe1ba 2003-11-23 devnull * or tags or anything else. Just mutable local blocks and immutable
12 056fe1ba 2003-11-23 devnull * Venti blocks.
15 056fe1ba 2003-11-23 devnull #include <u.h>
16 056fe1ba 2003-11-23 devnull #include <libc.h>
17 056fe1ba 2003-11-23 devnull #include <venti.h>
21 056fe1ba 2003-11-23 devnull MaxBlock = (1UL<<31),
24 056fe1ba 2003-11-23 devnull struct VtFile
26 056fe1ba 2003-11-23 devnull QLock lk;
28 056fe1ba 2003-11-23 devnull int local;
29 056fe1ba 2003-11-23 devnull VtBlock *b; /* block containing this file */
30 056fe1ba 2003-11-23 devnull uchar score[VtScoreSize]; /* score of block containing this file */
32 056fe1ba 2003-11-23 devnull /* immutable */
33 056fe1ba 2003-11-23 devnull VtCache *c;
34 056fe1ba 2003-11-23 devnull int mode;
35 056fe1ba 2003-11-23 devnull u32int gen;
36 056fe1ba 2003-11-23 devnull int dsize;
38 056fe1ba 2003-11-23 devnull VtFile *parent;
39 056fe1ba 2003-11-23 devnull int epb; /* entries per block in parent */
40 056fe1ba 2003-11-23 devnull u32int offset; /* entry offset in parent */
43 056fe1ba 2003-11-23 devnull static char EBadEntry[] = "bad VtEntry";
44 056fe1ba 2003-11-23 devnull static char ENotDir[] = "walk in non-directory";
45 056fe1ba 2003-11-23 devnull static char ETooBig[] = "file too big";
46 056fe1ba 2003-11-23 devnull static char EBadAddr[] = "bad address";
47 056fe1ba 2003-11-23 devnull static char ELabelMismatch[] = "label mismatch";
49 056fe1ba 2003-11-23 devnull static int sizetodepth(uvlong s, int psize, int dsize);
50 056fe1ba 2003-11-23 devnull static VtBlock *fileload(VtFile *r, VtEntry *e);
51 056fe1ba 2003-11-23 devnull static int shrinkdepth(VtFile*, VtBlock*, VtEntry*, int);
52 056fe1ba 2003-11-23 devnull static int shrinksize(VtFile*, VtEntry*, uvlong);
53 056fe1ba 2003-11-23 devnull static int growdepth(VtFile*, VtBlock*, VtEntry*, int);
55 056fe1ba 2003-11-23 devnull #define ISLOCKED(r) ((r)->b != nil)
56 056fe1ba 2003-11-23 devnull #define DEPTH(t) ((t)&VtTypeDepthMask)
58 056fe1ba 2003-11-23 devnull static VtFile *
59 056fe1ba 2003-11-23 devnull vtfilealloc(VtCache *c, VtBlock *b, VtFile *p, u32int offset, int mode)
62 056fe1ba 2003-11-23 devnull u32int size;
63 056fe1ba 2003-11-23 devnull VtEntry e;
64 056fe1ba 2003-11-23 devnull VtFile *r;
66 056fe1ba 2003-11-23 devnull assert(p==nil || ISLOCKED(p));
68 056fe1ba 2003-11-23 devnull if(p == nil){
69 056fe1ba 2003-11-23 devnull assert(offset == 0);
72 056fe1ba 2003-11-23 devnull epb = p->dsize / VtEntrySize;
74 056fe1ba 2003-11-23 devnull if(b->type != VtDirType)
75 056fe1ba 2003-11-23 devnull goto Bad;
78 056fe1ba 2003-11-23 devnull * a non-active entry is the only thing that
79 056fe1ba 2003-11-23 devnull * can legitimately happen here. all the others
80 056fe1ba 2003-11-23 devnull * get prints.
82 056fe1ba 2003-11-23 devnull if(vtentryunpack(&e, b->data, offset % epb) < 0){
83 056fe1ba 2003-11-23 devnull fprint(2, "vtentryunpack failed\n");
84 056fe1ba 2003-11-23 devnull goto Bad;
86 056fe1ba 2003-11-23 devnull if(!(e.flags & VtEntryActive)){
87 056fe1ba 2003-11-23 devnull if(0)fprint(2, "not active\n");
88 056fe1ba 2003-11-23 devnull goto Bad;
90 056fe1ba 2003-11-23 devnull if(e.psize < 256 || e.dsize < 256){
91 056fe1ba 2003-11-23 devnull fprint(2, "psize %ud dsize %ud\n", e.psize, e.dsize);
92 056fe1ba 2003-11-23 devnull goto Bad;
95 056fe1ba 2003-11-23 devnull if(DEPTH(e.type) < sizetodepth(e.size, e.psize, e.dsize)){
96 056fe1ba 2003-11-23 devnull fprint(2, "depth %ud size %llud psize %ud dsize %ud\n",
97 056fe1ba 2003-11-23 devnull DEPTH(e.type), e.size, e.psize, e.dsize);
98 056fe1ba 2003-11-23 devnull goto Bad;
101 056fe1ba 2003-11-23 devnull size = vtcacheblocksize(c);
102 056fe1ba 2003-11-23 devnull if(e.dsize > size || e.psize > size){
103 056fe1ba 2003-11-23 devnull fprint(2, "psize %ud dsize %ud blocksize %ud\n", e.psize, e.dsize, size);
104 056fe1ba 2003-11-23 devnull goto Bad;
107 056fe1ba 2003-11-23 devnull r = vtmallocz(sizeof(VtFile));
108 056fe1ba 2003-11-23 devnull r->c = c;
109 056fe1ba 2003-11-23 devnull r->mode = mode;
110 056fe1ba 2003-11-23 devnull r->dsize = e.dsize;
111 056fe1ba 2003-11-23 devnull r->gen = e.gen;
112 056fe1ba 2003-11-23 devnull r->dir = (e.flags & VtEntryDir) != 0;
113 056fe1ba 2003-11-23 devnull r->ref = 1;
114 056fe1ba 2003-11-23 devnull r->parent = p;
116 056fe1ba 2003-11-23 devnull qlock(&p->lk);
117 056fe1ba 2003-11-23 devnull assert(mode == VtOREAD || p->mode == VtORDWR);
118 056fe1ba 2003-11-23 devnull p->ref++;
119 056fe1ba 2003-11-23 devnull qunlock(&p->lk);
121 056fe1ba 2003-11-23 devnull memmove(r->score, b->score, VtScoreSize);
122 056fe1ba 2003-11-23 devnull r->offset = offset;
123 056fe1ba 2003-11-23 devnull r->epb = epb;
125 056fe1ba 2003-11-23 devnull return r;
127 056fe1ba 2003-11-23 devnull werrstr(EBadEntry);
128 056fe1ba 2003-11-23 devnull return nil;
132 056fe1ba 2003-11-23 devnull VtFile *
133 056fe1ba 2003-11-23 devnull vtfileroot(VtCache *c, u32int addr, int mode)
135 056fe1ba 2003-11-23 devnull VtFile *r;
136 056fe1ba 2003-11-23 devnull VtBlock *b;
138 056fe1ba 2003-11-23 devnull b = vtcachelocal(c, addr, VtDirType);
139 056fe1ba 2003-11-23 devnull if(b == nil)
140 056fe1ba 2003-11-23 devnull return nil;
142 056fe1ba 2003-11-23 devnull r = vtfilealloc(c, b, nil, 0, mode);
143 056fe1ba 2003-11-23 devnull vtblockput(b);
144 056fe1ba 2003-11-23 devnull return r;
148 056fe1ba 2003-11-23 devnull vtfileopenroot(VtCache *c, VtEntry *e)
150 056fe1ba 2003-11-23 devnull VtBlock *b;
151 056fe1ba 2003-11-23 devnull VtFile *f;
153 056fe1ba 2003-11-23 devnull b = vtcacheallocblock(c, VtDirType);
154 056fe1ba 2003-11-23 devnull if(b == nil)
155 056fe1ba 2003-11-23 devnull return nil;
157 056fe1ba 2003-11-23 devnull vtentrypack(e, b->data, 0);
158 056fe1ba 2003-11-23 devnull f = vtfilealloc(c, b, nil, 0, VtORDWR);
159 056fe1ba 2003-11-23 devnull vtblockput(b);
160 056fe1ba 2003-11-23 devnull return f;
163 056fe1ba 2003-11-23 devnull VtFile *
164 056fe1ba 2003-11-23 devnull vtfilecreateroot(VtCache *c, int psize, int dsize, int type)
166 056fe1ba 2003-11-23 devnull VtEntry e;
168 056fe1ba 2003-11-23 devnull memset(&e, 0, sizeof e);
169 056fe1ba 2003-11-23 devnull e.flags = VtEntryActive;
170 056fe1ba 2003-11-23 devnull e.psize = psize;
171 056fe1ba 2003-11-23 devnull e.dsize = dsize;
172 056fe1ba 2003-11-23 devnull if(type == VtDirType)
173 056fe1ba 2003-11-23 devnull e.flags |= VtEntryDir;
174 056fe1ba 2003-11-23 devnull memmove(e.score, vtzeroscore, VtScoreSize);
176 056fe1ba 2003-11-23 devnull return vtfileopenroot(c, &e);
179 056fe1ba 2003-11-23 devnull VtFile *
180 056fe1ba 2003-11-23 devnull vtfileopen(VtFile *r, u32int offset, int mode)
182 056fe1ba 2003-11-23 devnull ulong bn;
183 056fe1ba 2003-11-23 devnull VtBlock *b;
185 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
186 056fe1ba 2003-11-23 devnull if(!r->dir){
187 056fe1ba 2003-11-23 devnull werrstr(ENotDir);
188 056fe1ba 2003-11-23 devnull return nil;
191 056fe1ba 2003-11-23 devnull bn = offset/(r->dsize/VtEntrySize);
193 056fe1ba 2003-11-23 devnull b = vtfileblock(r, bn, mode);
194 056fe1ba 2003-11-23 devnull if(b == nil)
195 056fe1ba 2003-11-23 devnull return nil;
196 056fe1ba 2003-11-23 devnull r = vtfilealloc(r->c, b, r, offset, mode);
197 056fe1ba 2003-11-23 devnull vtblockput(b);
198 056fe1ba 2003-11-23 devnull return r;
201 056fe1ba 2003-11-23 devnull VtFile *
202 056fe1ba 2003-11-23 devnull vtfilecreate(VtFile *r, int psize, int dsize, int dir)
205 056fe1ba 2003-11-23 devnull VtBlock *b;
206 056fe1ba 2003-11-23 devnull u32int bn, size;
207 056fe1ba 2003-11-23 devnull VtEntry e;
208 056fe1ba 2003-11-23 devnull int epb;
209 056fe1ba 2003-11-23 devnull VtFile *rr;
210 056fe1ba 2003-11-23 devnull u32int offset;
212 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
214 056fe1ba 2003-11-23 devnull if(!r->dir){
215 056fe1ba 2003-11-23 devnull werrstr(ENotDir);
216 056fe1ba 2003-11-23 devnull return nil;
219 056fe1ba 2003-11-23 devnull epb = r->dsize/VtEntrySize;
221 056fe1ba 2003-11-23 devnull size = vtfilegetdirsize(r);
223 056fe1ba 2003-11-23 devnull * look at a random block to see if we can find an empty entry
225 056fe1ba 2003-11-23 devnull offset = lnrand(size+1);
226 056fe1ba 2003-11-23 devnull offset -= offset % epb;
228 056fe1ba 2003-11-23 devnull /* try the given block and then try the last block */
229 056fe1ba 2003-11-23 devnull for(;;){
230 056fe1ba 2003-11-23 devnull bn = offset/epb;
231 056fe1ba 2003-11-23 devnull b = vtfileblock(r, bn, VtORDWR);
232 056fe1ba 2003-11-23 devnull if(b == nil)
233 056fe1ba 2003-11-23 devnull return nil;
234 056fe1ba 2003-11-23 devnull for(i=offset%r->epb; i<epb; i++){
235 056fe1ba 2003-11-23 devnull if(vtentryunpack(&e, b->data, i) < 0)
236 056fe1ba 2003-11-23 devnull continue;
237 056fe1ba 2003-11-23 devnull if((e.flags&VtEntryActive) == 0 && e.gen != ~0)
238 056fe1ba 2003-11-23 devnull goto Found;
240 056fe1ba 2003-11-23 devnull vtblockput(b);
241 056fe1ba 2003-11-23 devnull if(offset == size){
242 056fe1ba 2003-11-23 devnull fprint(2, "vtfilecreate: cannot happen\n");
243 056fe1ba 2003-11-23 devnull werrstr("vtfilecreate: cannot happen");
244 056fe1ba 2003-11-23 devnull return nil;
246 056fe1ba 2003-11-23 devnull offset = size;
250 056fe1ba 2003-11-23 devnull /* found an entry - gen already set */
251 056fe1ba 2003-11-23 devnull e.psize = psize;
252 056fe1ba 2003-11-23 devnull e.dsize = dsize;
253 056fe1ba 2003-11-23 devnull e.flags = VtEntryActive;
254 056fe1ba 2003-11-23 devnull e.type = dir ? VtDirType : VtDataType;
255 056fe1ba 2003-11-23 devnull e.size = 0;
256 056fe1ba 2003-11-23 devnull memmove(e.score, vtzeroscore, VtScoreSize);
257 056fe1ba 2003-11-23 devnull vtentrypack(&e, b->data, i);
259 056fe1ba 2003-11-23 devnull offset = bn*epb + i;
260 056fe1ba 2003-11-23 devnull if(offset+1 > size){
261 056fe1ba 2003-11-23 devnull if(vtfilesetdirsize(r, offset+1) < 0){
262 056fe1ba 2003-11-23 devnull vtblockput(b);
263 056fe1ba 2003-11-23 devnull return nil;
267 056fe1ba 2003-11-23 devnull rr = vtfilealloc(r->c, b, r, offset, VtORDWR);
268 056fe1ba 2003-11-23 devnull vtblockput(b);
269 056fe1ba 2003-11-23 devnull return rr;
272 056fe1ba 2003-11-23 devnull static int
273 056fe1ba 2003-11-23 devnull vtfilekill(VtFile *r, int doremove)
275 056fe1ba 2003-11-23 devnull VtEntry e;
276 056fe1ba 2003-11-23 devnull VtBlock *b;
278 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
279 056fe1ba 2003-11-23 devnull b = fileload(r, &e);
280 056fe1ba 2003-11-23 devnull if(b == nil)
281 056fe1ba 2003-11-23 devnull return -1;
283 056fe1ba 2003-11-23 devnull if(doremove==0 && e.size == 0){
284 056fe1ba 2003-11-23 devnull /* already truncated */
285 056fe1ba 2003-11-23 devnull vtblockput(b);
286 056fe1ba 2003-11-23 devnull return 0;
289 056fe1ba 2003-11-23 devnull if(doremove){
290 056fe1ba 2003-11-23 devnull if(e.gen != ~0)
291 056fe1ba 2003-11-23 devnull e.gen++;
292 056fe1ba 2003-11-23 devnull e.dsize = 0;
293 056fe1ba 2003-11-23 devnull e.psize = 0;
294 056fe1ba 2003-11-23 devnull e.flags = 0;
296 056fe1ba 2003-11-23 devnull e.flags &= ~VtEntryLocal;
297 056fe1ba 2003-11-23 devnull e.type = 0;
298 056fe1ba 2003-11-23 devnull e.size = 0;
299 056fe1ba 2003-11-23 devnull memmove(e.score, vtzeroscore, VtScoreSize);
300 056fe1ba 2003-11-23 devnull vtentrypack(&e, b->data, r->offset % r->epb);
301 056fe1ba 2003-11-23 devnull vtblockput(b);
303 056fe1ba 2003-11-23 devnull if(doremove){
304 056fe1ba 2003-11-23 devnull vtfileunlock(r);
305 056fe1ba 2003-11-23 devnull vtfileclose(r);
308 056fe1ba 2003-11-23 devnull return 0;
312 056fe1ba 2003-11-23 devnull vtfileremove(VtFile *r)
314 056fe1ba 2003-11-23 devnull return vtfilekill(r, 1);
318 056fe1ba 2003-11-23 devnull vtfiletruncate(VtFile *r)
320 056fe1ba 2003-11-23 devnull return vtfilekill(r, 0);
324 056fe1ba 2003-11-23 devnull vtfilegetsize(VtFile *r)
326 056fe1ba 2003-11-23 devnull VtEntry e;
327 056fe1ba 2003-11-23 devnull VtBlock *b;
329 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
330 056fe1ba 2003-11-23 devnull b = fileload(r, &e);
331 056fe1ba 2003-11-23 devnull if(b == nil)
332 056fe1ba 2003-11-23 devnull return ~(uvlong)0;
333 056fe1ba 2003-11-23 devnull vtblockput(b);
335 056fe1ba 2003-11-23 devnull return e.size;
338 056fe1ba 2003-11-23 devnull static int
339 056fe1ba 2003-11-23 devnull shrinksize(VtFile *r, VtEntry *e, uvlong size)
341 056fe1ba 2003-11-23 devnull int i, depth, type, isdir, ppb;
342 056fe1ba 2003-11-23 devnull uvlong ptrsz;
343 056fe1ba 2003-11-23 devnull uchar score[VtScoreSize];
344 056fe1ba 2003-11-23 devnull VtBlock *b;
346 056fe1ba 2003-11-23 devnull b = vtcacheglobal(r->c, e->score, e->type);
347 056fe1ba 2003-11-23 devnull if(b == nil)
348 056fe1ba 2003-11-23 devnull return -1;
350 056fe1ba 2003-11-23 devnull ptrsz = e->dsize;
351 056fe1ba 2003-11-23 devnull ppb = e->psize/VtScoreSize;
352 056fe1ba 2003-11-23 devnull type = e->type;
353 056fe1ba 2003-11-23 devnull depth = DEPTH(type);
354 056fe1ba 2003-11-23 devnull for(i=0; i+1<depth; i++)
355 056fe1ba 2003-11-23 devnull ptrsz *= ppb;
357 056fe1ba 2003-11-23 devnull isdir = r->dir;
358 056fe1ba 2003-11-23 devnull while(depth > 0){
359 056fe1ba 2003-11-23 devnull if(b->addr == NilBlock){
360 056fe1ba 2003-11-23 devnull /* not worth copying the block just so we can zero some of it */
361 056fe1ba 2003-11-23 devnull vtblockput(b);
362 056fe1ba 2003-11-23 devnull return -1;
366 056fe1ba 2003-11-23 devnull * invariant: each pointer in the tree rooted at b accounts for ptrsz bytes
369 056fe1ba 2003-11-23 devnull /* zero the pointers to unnecessary blocks */
370 056fe1ba 2003-11-23 devnull i = (size+ptrsz-1)/ptrsz;
371 056fe1ba 2003-11-23 devnull for(; i<ppb; i++)
372 056fe1ba 2003-11-23 devnull memmove(b->data+i*VtScoreSize, vtzeroscore, VtScoreSize);
374 056fe1ba 2003-11-23 devnull /* recurse (go around again) on the partially necessary block */
375 056fe1ba 2003-11-23 devnull i = size/ptrsz;
376 056fe1ba 2003-11-23 devnull size = size%ptrsz;
377 056fe1ba 2003-11-23 devnull if(size == 0){
378 056fe1ba 2003-11-23 devnull vtblockput(b);
379 056fe1ba 2003-11-23 devnull return 0;
381 056fe1ba 2003-11-23 devnull ptrsz /= ppb;
383 056fe1ba 2003-11-23 devnull memmove(score, b->data+i*VtScoreSize, VtScoreSize);
384 056fe1ba 2003-11-23 devnull vtblockput(b);
385 056fe1ba 2003-11-23 devnull b = vtcacheglobal(r->c, score, type);
386 056fe1ba 2003-11-23 devnull if(b == nil)
387 056fe1ba 2003-11-23 devnull return -1;
390 056fe1ba 2003-11-23 devnull if(b->addr == NilBlock){
391 056fe1ba 2003-11-23 devnull vtblockput(b);
392 056fe1ba 2003-11-23 devnull return -1;
396 056fe1ba 2003-11-23 devnull * No one ever truncates BtDir blocks.
398 056fe1ba 2003-11-23 devnull if(depth==0 && !isdir && e->dsize > size)
399 056fe1ba 2003-11-23 devnull memset(b->data+size, 0, e->dsize-size);
400 056fe1ba 2003-11-23 devnull vtblockput(b);
401 056fe1ba 2003-11-23 devnull return 0;
405 056fe1ba 2003-11-23 devnull vtfilesetsize(VtFile *r, uvlong size)
407 056fe1ba 2003-11-23 devnull int depth, edepth;
408 056fe1ba 2003-11-23 devnull VtEntry e;
409 056fe1ba 2003-11-23 devnull VtBlock *b;
411 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
412 056fe1ba 2003-11-23 devnull if(size == 0)
413 056fe1ba 2003-11-23 devnull return vtfiletruncate(r);
415 056fe1ba 2003-11-23 devnull if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize){
416 056fe1ba 2003-11-23 devnull werrstr(ETooBig);
417 056fe1ba 2003-11-23 devnull return -1;
420 056fe1ba 2003-11-23 devnull b = fileload(r, &e);
421 056fe1ba 2003-11-23 devnull if(b == nil)
422 056fe1ba 2003-11-23 devnull return -1;
424 056fe1ba 2003-11-23 devnull /* quick out */
425 056fe1ba 2003-11-23 devnull if(e.size == size){
426 056fe1ba 2003-11-23 devnull vtblockput(b);
427 056fe1ba 2003-11-23 devnull return 0;
430 056fe1ba 2003-11-23 devnull depth = sizetodepth(size, e.psize, e.dsize);
431 056fe1ba 2003-11-23 devnull edepth = DEPTH(e.type);
432 056fe1ba 2003-11-23 devnull if(depth < edepth){
433 056fe1ba 2003-11-23 devnull if(shrinkdepth(r, b, &e, depth) < 0){
434 056fe1ba 2003-11-23 devnull vtblockput(b);
435 056fe1ba 2003-11-23 devnull return -1;
437 056fe1ba 2003-11-23 devnull }else if(depth > edepth){
438 056fe1ba 2003-11-23 devnull if(growdepth(r, b, &e, depth) < 0){
439 056fe1ba 2003-11-23 devnull vtblockput(b);
440 056fe1ba 2003-11-23 devnull return -1;
444 056fe1ba 2003-11-23 devnull if(size < e.size)
445 056fe1ba 2003-11-23 devnull shrinksize(r, &e, size);
447 056fe1ba 2003-11-23 devnull e.size = size;
448 056fe1ba 2003-11-23 devnull vtentrypack(&e, b->data, r->offset % r->epb);
449 056fe1ba 2003-11-23 devnull vtblockput(b);
451 056fe1ba 2003-11-23 devnull return 0;
455 056fe1ba 2003-11-23 devnull vtfilesetdirsize(VtFile *r, u32int ds)
457 056fe1ba 2003-11-23 devnull uvlong size;
458 056fe1ba 2003-11-23 devnull int epb;
460 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
461 056fe1ba 2003-11-23 devnull epb = r->dsize/VtEntrySize;
463 056fe1ba 2003-11-23 devnull size = (uvlong)r->dsize*(ds/epb);
464 056fe1ba 2003-11-23 devnull size += VtEntrySize*(ds%epb);
465 056fe1ba 2003-11-23 devnull return vtfilesetsize(r, size);
469 056fe1ba 2003-11-23 devnull vtfilegetdirsize(VtFile *r)
471 056fe1ba 2003-11-23 devnull ulong ds;
472 056fe1ba 2003-11-23 devnull uvlong size;
473 056fe1ba 2003-11-23 devnull int epb;
475 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
476 056fe1ba 2003-11-23 devnull epb = r->dsize/VtEntrySize;
478 056fe1ba 2003-11-23 devnull size = vtfilegetsize(r);
479 056fe1ba 2003-11-23 devnull ds = epb*(size/r->dsize);
480 056fe1ba 2003-11-23 devnull ds += (size%r->dsize)/VtEntrySize;
481 056fe1ba 2003-11-23 devnull return ds;
485 056fe1ba 2003-11-23 devnull vtfilegetentry(VtFile *r, VtEntry *e)
487 056fe1ba 2003-11-23 devnull VtBlock *b;
489 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
490 056fe1ba 2003-11-23 devnull b = fileload(r, e);
491 056fe1ba 2003-11-23 devnull if(b == nil)
492 056fe1ba 2003-11-23 devnull return -1;
493 056fe1ba 2003-11-23 devnull vtblockput(b);
495 056fe1ba 2003-11-23 devnull return 0;
499 056fe1ba 2003-11-23 devnull vtfilesetentry(VtFile *r, VtEntry *e)
501 056fe1ba 2003-11-23 devnull VtBlock *b;
502 056fe1ba 2003-11-23 devnull VtEntry ee;
504 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
505 056fe1ba 2003-11-23 devnull b = fileload(r, &ee);
506 056fe1ba 2003-11-23 devnull if(b == nil)
507 056fe1ba 2003-11-23 devnull return -1;
508 056fe1ba 2003-11-23 devnull vtentrypack(e, b->data, r->offset % r->epb);
509 056fe1ba 2003-11-23 devnull vtblockput(b);
510 056fe1ba 2003-11-23 devnull return 0;
513 056fe1ba 2003-11-23 devnull static VtBlock *
514 056fe1ba 2003-11-23 devnull blockwalk(VtBlock *p, int index, VtCache *c, int mode, VtEntry *e)
516 056fe1ba 2003-11-23 devnull VtBlock *b;
517 056fe1ba 2003-11-23 devnull int type;
518 056fe1ba 2003-11-23 devnull uchar *score;
519 056fe1ba 2003-11-23 devnull VtEntry oe;
521 056fe1ba 2003-11-23 devnull switch(p->type){
522 056fe1ba 2003-11-23 devnull case VtDataType:
523 056fe1ba 2003-11-23 devnull assert(0);
524 056fe1ba 2003-11-23 devnull case VtDirType:
525 056fe1ba 2003-11-23 devnull type = e->type;
526 056fe1ba 2003-11-23 devnull score = e->score;
528 056fe1ba 2003-11-23 devnull default:
529 056fe1ba 2003-11-23 devnull type = p->type - 1;
530 056fe1ba 2003-11-23 devnull score = p->data+index*VtScoreSize;
533 056fe1ba 2003-11-23 devnull //print("walk from %V/%d ty %d to %V ty %d\n", p->score, index, p->type, score, type);
535 056fe1ba 2003-11-23 devnull if(mode == VtOWRITE && vtglobaltolocal(score) == NilBlock){
536 056fe1ba 2003-11-23 devnull b = vtcacheallocblock(c, type);
538 056fe1ba 2003-11-23 devnull goto HaveCopy;
540 056fe1ba 2003-11-23 devnull b = vtcacheglobal(c, score, type);
542 056fe1ba 2003-11-23 devnull if(b == nil || mode == VtOREAD)
543 056fe1ba 2003-11-23 devnull return b;
545 056fe1ba 2003-11-23 devnull if(vtglobaltolocal(b->score) != NilBlock)
546 056fe1ba 2003-11-23 devnull return b;
548 056fe1ba 2003-11-23 devnull oe = *e;
551 056fe1ba 2003-11-23 devnull * Copy on write.
553 056fe1ba 2003-11-23 devnull e->flags |= VtEntryLocal;
555 056fe1ba 2003-11-23 devnull b = vtblockcopy(b/*, e->tag, fs->ehi, fs->elo*/);
556 056fe1ba 2003-11-23 devnull if(b == nil)
557 056fe1ba 2003-11-23 devnull return nil;
559 056fe1ba 2003-11-23 devnull HaveCopy:
560 056fe1ba 2003-11-23 devnull if(p->type == VtDirType){
561 056fe1ba 2003-11-23 devnull memmove(e->score, b->score, VtScoreSize);
562 056fe1ba 2003-11-23 devnull vtentrypack(e, p->data, index);
564 056fe1ba 2003-11-23 devnull memmove(p->data+index*VtScoreSize, b->score, VtScoreSize);
566 056fe1ba 2003-11-23 devnull return b;
570 056fe1ba 2003-11-23 devnull * Change the depth of the VtFile r.
571 056fe1ba 2003-11-23 devnull * The entry e for r is contained in block p.
573 056fe1ba 2003-11-23 devnull static int
574 056fe1ba 2003-11-23 devnull growdepth(VtFile *r, VtBlock *p, VtEntry *e, int depth)
576 056fe1ba 2003-11-23 devnull VtBlock *b, *bb;
577 056fe1ba 2003-11-23 devnull VtEntry oe;
579 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
580 056fe1ba 2003-11-23 devnull assert(depth <= VtPointerDepth);
582 056fe1ba 2003-11-23 devnull b = vtcacheglobal(r->c, e->score, e->type);
583 056fe1ba 2003-11-23 devnull if(b == nil)
584 056fe1ba 2003-11-23 devnull return -1;
586 056fe1ba 2003-11-23 devnull oe = *e;
589 056fe1ba 2003-11-23 devnull * Keep adding layers until we get to the right depth
590 056fe1ba 2003-11-23 devnull * or an error occurs.
592 056fe1ba 2003-11-23 devnull while(DEPTH(e->type) < depth){
593 056fe1ba 2003-11-23 devnull bb = vtcacheallocblock(r->c, e->type+1);
594 056fe1ba 2003-11-23 devnull if(bb == nil)
596 056fe1ba 2003-11-23 devnull memmove(bb->data, b->score, VtScoreSize);
597 056fe1ba 2003-11-23 devnull memmove(e->score, bb->score, VtScoreSize);
598 056fe1ba 2003-11-23 devnull e->type++;
599 056fe1ba 2003-11-23 devnull e->flags |= VtEntryLocal;
600 056fe1ba 2003-11-23 devnull vtblockput(b);
604 056fe1ba 2003-11-23 devnull vtentrypack(e, p->data, r->offset % r->epb);
605 056fe1ba 2003-11-23 devnull vtblockput(b);
607 056fe1ba 2003-11-23 devnull if(DEPTH(e->type) == depth)
608 056fe1ba 2003-11-23 devnull return 0;
609 056fe1ba 2003-11-23 devnull return -1;
612 056fe1ba 2003-11-23 devnull static int
613 056fe1ba 2003-11-23 devnull shrinkdepth(VtFile *r, VtBlock *p, VtEntry *e, int depth)
615 056fe1ba 2003-11-23 devnull VtBlock *b, *nb, *ob, *rb;
616 056fe1ba 2003-11-23 devnull VtEntry oe;
618 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
619 056fe1ba 2003-11-23 devnull assert(depth <= VtPointerDepth);
621 056fe1ba 2003-11-23 devnull rb = vtcacheglobal(r->c, e->score, e->type);
622 056fe1ba 2003-11-23 devnull if(rb == nil)
623 056fe1ba 2003-11-23 devnull return 0;
626 056fe1ba 2003-11-23 devnull * Walk down to the new root block.
627 056fe1ba 2003-11-23 devnull * We may stop early, but something is better than nothing.
629 056fe1ba 2003-11-23 devnull oe = *e;
631 056fe1ba 2003-11-23 devnull ob = nil;
633 056fe1ba 2003-11-23 devnull for(; DEPTH(e->type) > depth; e->type--){
634 056fe1ba 2003-11-23 devnull nb = vtcacheglobal(r->c, b->data, e->type-1);
635 056fe1ba 2003-11-23 devnull if(nb == nil)
637 056fe1ba 2003-11-23 devnull if(ob!=nil && ob!=rb)
638 056fe1ba 2003-11-23 devnull vtblockput(ob);
643 056fe1ba 2003-11-23 devnull if(b == rb){
644 056fe1ba 2003-11-23 devnull vtblockput(rb);
645 056fe1ba 2003-11-23 devnull return 0;
649 056fe1ba 2003-11-23 devnull * Right now, e points at the root block rb, b is the new root block,
650 056fe1ba 2003-11-23 devnull * and ob points at b. To update:
652 056fe1ba 2003-11-23 devnull * (i) change e to point at b
653 056fe1ba 2003-11-23 devnull * (ii) zero the pointer ob -> b
654 056fe1ba 2003-11-23 devnull * (iii) free the root block
656 056fe1ba 2003-11-23 devnull * p (the block containing e) must be written before
657 056fe1ba 2003-11-23 devnull * anything else.
660 056fe1ba 2003-11-23 devnull /* (i) */
661 056fe1ba 2003-11-23 devnull memmove(e->score, b->score, VtScoreSize);
662 056fe1ba 2003-11-23 devnull vtentrypack(e, p->data, r->offset % r->epb);
664 056fe1ba 2003-11-23 devnull /* (ii) */
665 056fe1ba 2003-11-23 devnull memmove(ob->data, vtzeroscore, VtScoreSize);
667 056fe1ba 2003-11-23 devnull /* (iii) */
668 056fe1ba 2003-11-23 devnull vtblockput(rb);
669 056fe1ba 2003-11-23 devnull if(ob!=nil && ob!=rb)
670 056fe1ba 2003-11-23 devnull vtblockput(ob);
671 056fe1ba 2003-11-23 devnull vtblockput(b);
673 056fe1ba 2003-11-23 devnull if(DEPTH(e->type) == depth)
674 056fe1ba 2003-11-23 devnull return 0;
675 056fe1ba 2003-11-23 devnull return -1;
678 056fe1ba 2003-11-23 devnull static int
679 056fe1ba 2003-11-23 devnull mkindices(VtEntry *e, u32int bn, int *index)
681 056fe1ba 2003-11-23 devnull int i, np;
683 056fe1ba 2003-11-23 devnull memset(index, 0, VtPointerDepth*sizeof(int));
685 056fe1ba 2003-11-23 devnull np = e->psize/VtScoreSize;
686 056fe1ba 2003-11-23 devnull for(i=0; bn > 0; i++){
687 056fe1ba 2003-11-23 devnull if(i >= VtPointerDepth){
688 056fe1ba 2003-11-23 devnull werrstr(EBadAddr);
689 056fe1ba 2003-11-23 devnull return -1;
691 056fe1ba 2003-11-23 devnull index[i] = bn % np;
692 056fe1ba 2003-11-23 devnull bn /= np;
694 056fe1ba 2003-11-23 devnull return i;
697 056fe1ba 2003-11-23 devnull VtBlock *
698 056fe1ba 2003-11-23 devnull vtfileblock(VtFile *r, u32int bn, int mode)
700 056fe1ba 2003-11-23 devnull VtBlock *b, *bb;
701 056fe1ba 2003-11-23 devnull int index[VtPointerDepth+1];
702 056fe1ba 2003-11-23 devnull VtEntry e;
706 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
707 056fe1ba 2003-11-23 devnull assert(bn != NilBlock);
709 056fe1ba 2003-11-23 devnull b = fileload(r, &e);
710 056fe1ba 2003-11-23 devnull if(b == nil)
711 056fe1ba 2003-11-23 devnull return nil;
713 056fe1ba 2003-11-23 devnull i = mkindices(&e, bn, index);
714 056fe1ba 2003-11-23 devnull if(i < 0)
715 056fe1ba 2003-11-23 devnull return nil;
716 056fe1ba 2003-11-23 devnull if(i > DEPTH(e.type)){
717 056fe1ba 2003-11-23 devnull if(mode == VtOREAD){
718 056fe1ba 2003-11-23 devnull werrstr(EBadAddr);
719 056fe1ba 2003-11-23 devnull goto Err;
721 056fe1ba 2003-11-23 devnull index[i] = 0;
722 056fe1ba 2003-11-23 devnull if(growdepth(r, b, &e, i) < 0)
723 056fe1ba 2003-11-23 devnull goto Err;
726 056fe1ba 2003-11-23 devnull assert(b->type == VtDirType);
728 056fe1ba 2003-11-23 devnull index[DEPTH(e.type)] = r->offset % r->epb;
730 056fe1ba 2003-11-23 devnull /* mode for intermediate block */
731 056fe1ba 2003-11-23 devnull m = mode;
732 056fe1ba 2003-11-23 devnull if(m == VtOWRITE)
733 056fe1ba 2003-11-23 devnull m = VtORDWR;
735 056fe1ba 2003-11-23 devnull for(i=DEPTH(e.type); i>=0; i--){
736 056fe1ba 2003-11-23 devnull bb = blockwalk(b, index[i], r->c, i==0 ? mode : m, &e);
737 056fe1ba 2003-11-23 devnull if(bb == nil)
738 056fe1ba 2003-11-23 devnull goto Err;
739 056fe1ba 2003-11-23 devnull vtblockput(b);
742 056fe1ba 2003-11-23 devnull return b;
744 056fe1ba 2003-11-23 devnull vtblockput(b);
745 056fe1ba 2003-11-23 devnull return nil;
749 056fe1ba 2003-11-23 devnull vtfileblockhash(VtFile *r, u32int bn, uchar score[VtScoreSize])
751 056fe1ba 2003-11-23 devnull VtBlock *b, *bb;
752 056fe1ba 2003-11-23 devnull int index[VtPointerDepth+1];
753 056fe1ba 2003-11-23 devnull VtEntry e;
756 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
757 056fe1ba 2003-11-23 devnull assert(bn != NilBlock);
759 056fe1ba 2003-11-23 devnull b = fileload(r, &e);
760 056fe1ba 2003-11-23 devnull if(b == nil)
761 056fe1ba 2003-11-23 devnull return -1;
763 056fe1ba 2003-11-23 devnull i = mkindices(&e, bn, index);
764 056fe1ba 2003-11-23 devnull if(i < 0){
765 056fe1ba 2003-11-23 devnull vtblockput(b);
766 056fe1ba 2003-11-23 devnull return -1;
768 056fe1ba 2003-11-23 devnull if(i > DEPTH(e.type)){
769 056fe1ba 2003-11-23 devnull memmove(score, vtzeroscore, VtScoreSize);
770 056fe1ba 2003-11-23 devnull vtblockput(b);
771 056fe1ba 2003-11-23 devnull return 0;
774 056fe1ba 2003-11-23 devnull index[DEPTH(e.type)] = r->offset % r->epb;
776 056fe1ba 2003-11-23 devnull for(i=DEPTH(e.type); i>=1; i--){
777 056fe1ba 2003-11-23 devnull bb = blockwalk(b, index[i], r->c, VtOREAD, &e);
778 056fe1ba 2003-11-23 devnull if(bb == nil)
779 056fe1ba 2003-11-23 devnull goto Err;
780 056fe1ba 2003-11-23 devnull vtblockput(b);
782 056fe1ba 2003-11-23 devnull if(memcmp(b->score, vtzeroscore, VtScoreSize) == 0)
786 056fe1ba 2003-11-23 devnull memmove(score, b->data+index[0]*VtScoreSize, VtScoreSize);
787 056fe1ba 2003-11-23 devnull vtblockput(b);
788 056fe1ba 2003-11-23 devnull return 0;
791 056fe1ba 2003-11-23 devnull fprint(2, "vtfileblockhash: %r\n");
792 056fe1ba 2003-11-23 devnull vtblockput(b);
793 056fe1ba 2003-11-23 devnull return -1;
797 056fe1ba 2003-11-23 devnull vtfileincref(VtFile *r)
799 056fe1ba 2003-11-23 devnull qlock(&r->lk);
800 056fe1ba 2003-11-23 devnull r->ref++;
801 056fe1ba 2003-11-23 devnull qunlock(&r->lk);
805 056fe1ba 2003-11-23 devnull vtfileclose(VtFile *r)
807 056fe1ba 2003-11-23 devnull if(r == nil)
809 056fe1ba 2003-11-23 devnull qlock(&r->lk);
810 056fe1ba 2003-11-23 devnull r->ref--;
811 056fe1ba 2003-11-23 devnull if(r->ref){
812 056fe1ba 2003-11-23 devnull qunlock(&r->lk);
815 056fe1ba 2003-11-23 devnull assert(r->ref == 0);
816 056fe1ba 2003-11-23 devnull qunlock(&r->lk);
817 056fe1ba 2003-11-23 devnull if(r->parent)
818 056fe1ba 2003-11-23 devnull vtfileclose(r->parent);
819 056fe1ba 2003-11-23 devnull memset(r, ~0, sizeof(*r));
820 056fe1ba 2003-11-23 devnull vtfree(r);
824 056fe1ba 2003-11-23 devnull * Retrieve the block containing the entry for r.
825 056fe1ba 2003-11-23 devnull * If a snapshot has happened, we might need
826 056fe1ba 2003-11-23 devnull * to get a new copy of the block. We avoid this
827 056fe1ba 2003-11-23 devnull * in the common case by caching the score for
828 056fe1ba 2003-11-23 devnull * the block and the last epoch in which it was valid.
830 056fe1ba 2003-11-23 devnull * We use r->mode to tell the difference between active
831 056fe1ba 2003-11-23 devnull * file system VtFiles (VtORDWR) and VtFiles for the
832 056fe1ba 2003-11-23 devnull * snapshot file system (VtOREAD).
834 056fe1ba 2003-11-23 devnull static VtBlock*
835 056fe1ba 2003-11-23 devnull fileloadblock(VtFile *r, int mode)
837 056fe1ba 2003-11-23 devnull char e[ERRMAX];
838 056fe1ba 2003-11-23 devnull u32int addr;
839 056fe1ba 2003-11-23 devnull VtBlock *b;
841 056fe1ba 2003-11-23 devnull switch(r->mode){
842 056fe1ba 2003-11-23 devnull default:
843 056fe1ba 2003-11-23 devnull assert(0);
844 056fe1ba 2003-11-23 devnull case VtORDWR:
845 056fe1ba 2003-11-23 devnull assert(r->mode == VtORDWR);
846 056fe1ba 2003-11-23 devnull if(r->local == 1){
847 056fe1ba 2003-11-23 devnull b = vtcacheglobal(r->c, r->score, VtDirType);
848 056fe1ba 2003-11-23 devnull if(b == nil)
849 056fe1ba 2003-11-23 devnull return nil;
850 056fe1ba 2003-11-23 devnull return b;
852 056fe1ba 2003-11-23 devnull assert(r->parent != nil);
853 056fe1ba 2003-11-23 devnull if(vtfilelock(r->parent, VtORDWR) < 0)
854 056fe1ba 2003-11-23 devnull return nil;
855 056fe1ba 2003-11-23 devnull b = vtfileblock(r->parent, r->offset/r->epb, VtORDWR);
856 056fe1ba 2003-11-23 devnull vtfileunlock(r->parent);
857 056fe1ba 2003-11-23 devnull if(b == nil)
858 056fe1ba 2003-11-23 devnull return nil;
859 056fe1ba 2003-11-23 devnull memmove(r->score, b->score, VtScoreSize);
860 056fe1ba 2003-11-23 devnull r->local = 1;
861 056fe1ba 2003-11-23 devnull return b;
863 056fe1ba 2003-11-23 devnull case VtOREAD:
864 056fe1ba 2003-11-23 devnull if(mode == VtORDWR){
865 056fe1ba 2003-11-23 devnull werrstr("read/write lock of read-only file");
866 056fe1ba 2003-11-23 devnull return nil;
868 056fe1ba 2003-11-23 devnull addr = vtglobaltolocal(r->score);
869 056fe1ba 2003-11-23 devnull if(addr == NilBlock)
870 056fe1ba 2003-11-23 devnull return vtcacheglobal(r->c, r->score, VtDirType);
872 056fe1ba 2003-11-23 devnull b = vtcachelocal(r->c, addr, VtDirType);
874 056fe1ba 2003-11-23 devnull return b;
877 056fe1ba 2003-11-23 devnull * If it failed because the epochs don't match, the block has been
878 056fe1ba 2003-11-23 devnull * archived and reclaimed. Rewalk from the parent and get the
879 056fe1ba 2003-11-23 devnull * new pointer. This can't happen in the VtORDWR case
880 056fe1ba 2003-11-23 devnull * above because blocks in the current epoch don't get
881 056fe1ba 2003-11-23 devnull * reclaimed. The fact that we're VtOREAD means we're
882 056fe1ba 2003-11-23 devnull * a snapshot. (Or else the file system is read-only, but then
883 056fe1ba 2003-11-23 devnull * the archiver isn't going around deleting blocks.)
885 056fe1ba 2003-11-23 devnull rerrstr(e, sizeof e);
886 056fe1ba 2003-11-23 devnull if(strcmp(e, ELabelMismatch) == 0){
887 056fe1ba 2003-11-23 devnull if(vtfilelock(r->parent, VtOREAD) < 0)
888 056fe1ba 2003-11-23 devnull return nil;
889 056fe1ba 2003-11-23 devnull b = vtfileblock(r->parent, r->offset/r->epb, VtOREAD);
890 056fe1ba 2003-11-23 devnull vtfileunlock(r->parent);
892 056fe1ba 2003-11-23 devnull fprint(2, "vtfilealloc: lost %V found %V\n",
893 056fe1ba 2003-11-23 devnull r->score, b->score);
894 056fe1ba 2003-11-23 devnull memmove(r->score, b->score, VtScoreSize);
895 056fe1ba 2003-11-23 devnull return b;
898 056fe1ba 2003-11-23 devnull return nil;
903 056fe1ba 2003-11-23 devnull vtfilelock(VtFile *r, int mode)
905 056fe1ba 2003-11-23 devnull VtBlock *b;
907 056fe1ba 2003-11-23 devnull if(mode == -1)
908 056fe1ba 2003-11-23 devnull mode = r->mode;
910 056fe1ba 2003-11-23 devnull b = fileloadblock(r, mode);
911 056fe1ba 2003-11-23 devnull if(b == nil)
912 056fe1ba 2003-11-23 devnull return -1;
914 056fe1ba 2003-11-23 devnull * The fact that we are holding b serves as the
915 056fe1ba 2003-11-23 devnull * lock entitling us to write to r->b.
917 056fe1ba 2003-11-23 devnull assert(r->b == nil);
918 056fe1ba 2003-11-23 devnull r->b = b;
919 056fe1ba 2003-11-23 devnull return 0;
923 056fe1ba 2003-11-23 devnull * Lock two (usually sibling) VtFiles. This needs special care
924 056fe1ba 2003-11-23 devnull * because the Entries for both vtFiles might be in the same block.
925 056fe1ba 2003-11-23 devnull * We also try to lock blocks in left-to-right order within the tree.
928 056fe1ba 2003-11-23 devnull vtfilelock2(VtFile *r, VtFile *rr, int mode)
930 056fe1ba 2003-11-23 devnull VtBlock *b, *bb;
932 056fe1ba 2003-11-23 devnull if(rr == nil)
933 056fe1ba 2003-11-23 devnull return vtfilelock(r, mode);
935 056fe1ba 2003-11-23 devnull if(mode == -1)
936 056fe1ba 2003-11-23 devnull mode = r->mode;
938 056fe1ba 2003-11-23 devnull if(r->parent==rr->parent && r->offset/r->epb == rr->offset/rr->epb){
939 056fe1ba 2003-11-23 devnull b = fileloadblock(r, mode);
940 056fe1ba 2003-11-23 devnull if(b == nil)
941 056fe1ba 2003-11-23 devnull return -1;
942 056fe1ba 2003-11-23 devnull vtblockduplock(b);
944 056fe1ba 2003-11-23 devnull }else if(r->parent==rr->parent || r->offset > rr->offset){
945 056fe1ba 2003-11-23 devnull bb = fileloadblock(rr, mode);
946 056fe1ba 2003-11-23 devnull b = fileloadblock(r, mode);
948 056fe1ba 2003-11-23 devnull b = fileloadblock(r, mode);
949 056fe1ba 2003-11-23 devnull bb = fileloadblock(rr, mode);
951 056fe1ba 2003-11-23 devnull if(b == nil || bb == nil){
953 056fe1ba 2003-11-23 devnull vtblockput(b);
955 056fe1ba 2003-11-23 devnull vtblockput(bb);
956 056fe1ba 2003-11-23 devnull return -1;
960 056fe1ba 2003-11-23 devnull * The fact that we are holding b and bb serves
961 056fe1ba 2003-11-23 devnull * as the lock entitling us to write to r->b and rr->b.
963 056fe1ba 2003-11-23 devnull r->b = b;
964 056fe1ba 2003-11-23 devnull rr->b = bb;
965 056fe1ba 2003-11-23 devnull return 0;
969 056fe1ba 2003-11-23 devnull vtfileunlock(VtFile *r)
971 056fe1ba 2003-11-23 devnull VtBlock *b;
973 056fe1ba 2003-11-23 devnull if(r->b == nil){
974 056fe1ba 2003-11-23 devnull fprint(2, "vtfileunlock: already unlocked\n");
975 056fe1ba 2003-11-23 devnull abort();
977 056fe1ba 2003-11-23 devnull b = r->b;
978 056fe1ba 2003-11-23 devnull r->b = nil;
979 056fe1ba 2003-11-23 devnull vtblockput(b);
982 056fe1ba 2003-11-23 devnull static VtBlock*
983 056fe1ba 2003-11-23 devnull fileload(VtFile *r, VtEntry *e)
985 056fe1ba 2003-11-23 devnull VtBlock *b;
987 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
988 056fe1ba 2003-11-23 devnull b = r->b;
989 056fe1ba 2003-11-23 devnull if(vtentryunpack(e, b->data, r->offset % r->epb) < 0)
990 056fe1ba 2003-11-23 devnull return nil;
991 056fe1ba 2003-11-23 devnull vtblockduplock(b);
992 056fe1ba 2003-11-23 devnull return b;
995 056fe1ba 2003-11-23 devnull static int
996 056fe1ba 2003-11-23 devnull sizetodepth(uvlong s, int psize, int dsize)
1001 056fe1ba 2003-11-23 devnull /* determine pointer depth */
1002 056fe1ba 2003-11-23 devnull np = psize/VtScoreSize;
1003 056fe1ba 2003-11-23 devnull s = (s + dsize - 1)/dsize;
1004 056fe1ba 2003-11-23 devnull for(d = 0; s > 1; d++)
1005 056fe1ba 2003-11-23 devnull s = (s + np - 1)/np;
1006 056fe1ba 2003-11-23 devnull return d;
1010 056fe1ba 2003-11-23 devnull vtfileread(VtFile *f, void *data, long count, vlong offset)
1012 056fe1ba 2003-11-23 devnull int frag;
1013 056fe1ba 2003-11-23 devnull VtBlock *b;
1014 056fe1ba 2003-11-23 devnull VtEntry e;
1016 056fe1ba 2003-11-23 devnull assert(ISLOCKED(f));
1018 056fe1ba 2003-11-23 devnull vtfilegetentry(f, &e);
1019 056fe1ba 2003-11-23 devnull if(count == 0)
1020 056fe1ba 2003-11-23 devnull return 0;
1021 056fe1ba 2003-11-23 devnull if(count < 0 || offset < 0){
1022 056fe1ba 2003-11-23 devnull werrstr("vtfileread: bad offset or count");
1023 056fe1ba 2003-11-23 devnull return -1;
1025 056fe1ba 2003-11-23 devnull if(offset >= e.size)
1026 056fe1ba 2003-11-23 devnull return 0;
1028 056fe1ba 2003-11-23 devnull if(offset+count > e.size)
1029 056fe1ba 2003-11-23 devnull count = e.size - offset;
1031 056fe1ba 2003-11-23 devnull frag = offset % e.dsize;
1032 056fe1ba 2003-11-23 devnull if(frag+count > e.dsize)
1033 056fe1ba 2003-11-23 devnull count = e.dsize - frag;
1035 056fe1ba 2003-11-23 devnull b = vtfileblock(f, offset/e.dsize, VtOREAD);
1036 056fe1ba 2003-11-23 devnull if(b == nil)
1037 056fe1ba 2003-11-23 devnull return -1;
1039 056fe1ba 2003-11-23 devnull memmove(data, b->data+frag, count);
1040 056fe1ba 2003-11-23 devnull vtblockput(b);
1041 056fe1ba 2003-11-23 devnull return count;
1044 056fe1ba 2003-11-23 devnull static long
1045 056fe1ba 2003-11-23 devnull filewrite1(VtFile *f, void *data, long count, vlong offset)
1047 056fe1ba 2003-11-23 devnull int frag, m;
1048 056fe1ba 2003-11-23 devnull VtBlock *b;
1049 056fe1ba 2003-11-23 devnull VtEntry e;
1051 056fe1ba 2003-11-23 devnull vtfilegetentry(f, &e);
1052 056fe1ba 2003-11-23 devnull if(count < 0 || offset < 0){
1053 056fe1ba 2003-11-23 devnull werrstr("vtfilewrite: bad offset or count");
1054 056fe1ba 2003-11-23 devnull return -1;
1057 056fe1ba 2003-11-23 devnull frag = offset % e.dsize;
1058 056fe1ba 2003-11-23 devnull if(frag+count > e.dsize)
1059 056fe1ba 2003-11-23 devnull count = e.dsize - frag;
1061 056fe1ba 2003-11-23 devnull m = VtORDWR;
1062 056fe1ba 2003-11-23 devnull if(frag == 0 && count == e.dsize)
1063 056fe1ba 2003-11-23 devnull m = VtOWRITE;
1065 056fe1ba 2003-11-23 devnull b = vtfileblock(f, offset/e.dsize, m);
1066 056fe1ba 2003-11-23 devnull if(b == nil)
1067 056fe1ba 2003-11-23 devnull return -1;
1069 056fe1ba 2003-11-23 devnull memmove(b->data+frag, data, count);
1071 056fe1ba 2003-11-23 devnull if(offset+count > e.size){
1072 056fe1ba 2003-11-23 devnull vtfilegetentry(f, &e);
1073 056fe1ba 2003-11-23 devnull e.size = offset+count;
1074 056fe1ba 2003-11-23 devnull vtfilesetentry(f, &e);
1077 056fe1ba 2003-11-23 devnull vtblockput(b);
1078 056fe1ba 2003-11-23 devnull return count;
1082 056fe1ba 2003-11-23 devnull vtfilewrite(VtFile *f, void *data, long count, vlong offset)
1084 056fe1ba 2003-11-23 devnull long tot, m;
1086 056fe1ba 2003-11-23 devnull assert(ISLOCKED(f));
1088 056fe1ba 2003-11-23 devnull tot = 0;
1090 056fe1ba 2003-11-23 devnull while(tot < count){
1091 056fe1ba 2003-11-23 devnull m = filewrite1(f, (char*)data+tot, count-tot, offset+tot);
1092 056fe1ba 2003-11-23 devnull if(m <= 0)
1094 056fe1ba 2003-11-23 devnull tot += m;
1096 056fe1ba 2003-11-23 devnull if(tot==0)
1097 056fe1ba 2003-11-23 devnull return m;
1098 056fe1ba 2003-11-23 devnull return tot;
1101 056fe1ba 2003-11-23 devnull static int
1102 056fe1ba 2003-11-23 devnull flushblock(VtCache *c, VtBlock *bb, uchar score[VtScoreSize], int ppb, int epb,
1103 056fe1ba 2003-11-23 devnull int type)
1105 056fe1ba 2003-11-23 devnull u32int addr;
1106 056fe1ba 2003-11-23 devnull VtBlock *b;
1107 056fe1ba 2003-11-23 devnull VtEntry e;
1110 056fe1ba 2003-11-23 devnull addr = vtglobaltolocal(score);
1111 056fe1ba 2003-11-23 devnull if(addr == NilBlock)
1112 056fe1ba 2003-11-23 devnull return 0;
1114 056fe1ba 2003-11-23 devnull if(bb){
1115 056fe1ba 2003-11-23 devnull b = bb;
1116 056fe1ba 2003-11-23 devnull if(memcmp(b->score, score, VtScoreSize) != 0)
1117 056fe1ba 2003-11-23 devnull abort();
1119 056fe1ba 2003-11-23 devnull if((b = vtcachelocal(c, addr, type)) == nil)
1120 056fe1ba 2003-11-23 devnull return -1;
1122 056fe1ba 2003-11-23 devnull switch(type){
1123 056fe1ba 2003-11-23 devnull case VtDataType:
1126 056fe1ba 2003-11-23 devnull case VtDirType:
1127 056fe1ba 2003-11-23 devnull for(i=0; i<epb; i++){
1128 056fe1ba 2003-11-23 devnull if(vtentryunpack(&e, b->data, i) < 0)
1129 056fe1ba 2003-11-23 devnull goto Err;
1130 056fe1ba 2003-11-23 devnull if(flushblock(c, nil, e.score, e.psize/VtScoreSize, e.dsize/VtEntrySize,
1131 056fe1ba 2003-11-23 devnull e.type) < 0)
1132 056fe1ba 2003-11-23 devnull goto Err;
1136 056fe1ba 2003-11-23 devnull default: /* VtPointerTypeX */
1137 056fe1ba 2003-11-23 devnull for(i=0; i<ppb; i++){
1138 056fe1ba 2003-11-23 devnull if(flushblock(c, nil, b->data+VtScoreSize*i, ppb, epb, type-1) < 0)
1139 056fe1ba 2003-11-23 devnull goto Err;
1144 056fe1ba 2003-11-23 devnull if(vtblockwrite(b) < 0)
1145 056fe1ba 2003-11-23 devnull goto Err;
1146 056fe1ba 2003-11-23 devnull memmove(score, b->score, VtScoreSize);
1147 056fe1ba 2003-11-23 devnull if(b != bb)
1148 056fe1ba 2003-11-23 devnull vtblockput(b);
1149 056fe1ba 2003-11-23 devnull return 0;
1152 056fe1ba 2003-11-23 devnull if(b != bb)
1153 056fe1ba 2003-11-23 devnull vtblockput(b);
1154 056fe1ba 2003-11-23 devnull return -1;
1158 056fe1ba 2003-11-23 devnull vtfileflush(VtFile *f)
1160 056fe1ba 2003-11-23 devnull int ret;
1161 056fe1ba 2003-11-23 devnull VtBlock *b;
1162 056fe1ba 2003-11-23 devnull VtEntry e;
1164 056fe1ba 2003-11-23 devnull assert(ISLOCKED(f));
1165 056fe1ba 2003-11-23 devnull b = fileload(f, &e);
1166 056fe1ba 2003-11-23 devnull if(!(e.flags&VtEntryLocal)){
1167 056fe1ba 2003-11-23 devnull vtblockput(b);
1168 056fe1ba 2003-11-23 devnull return 0;
1171 056fe1ba 2003-11-23 devnull ret = flushblock(f->c, nil, e.score, e.psize/VtScoreSize, e.dsize/VtEntrySize,
1172 056fe1ba 2003-11-23 devnull e.type);
1173 056fe1ba 2003-11-23 devnull if(!ret){
1174 056fe1ba 2003-11-23 devnull vtblockput(b);
1175 056fe1ba 2003-11-23 devnull return -1;
1178 056fe1ba 2003-11-23 devnull vtentrypack(&e, b->data, f->offset % f->epb);
1179 056fe1ba 2003-11-23 devnull vtblockput(b);
1180 056fe1ba 2003-11-23 devnull return 0;
1184 056fe1ba 2003-11-23 devnull vtfileflushbefore(VtFile *r, u64int offset)
1186 056fe1ba 2003-11-23 devnull VtBlock *b, *bb;
1187 056fe1ba 2003-11-23 devnull VtEntry e;
1188 056fe1ba 2003-11-23 devnull int i, base, depth, ppb, epb, ok;
1189 056fe1ba 2003-11-23 devnull int index[VtPointerDepth+1], index1[VtPointerDepth+1], j, ret;
1190 056fe1ba 2003-11-23 devnull VtBlock *bi[VtPointerDepth+2];
1191 056fe1ba 2003-11-23 devnull uchar *score;
1193 056fe1ba 2003-11-23 devnull assert(ISLOCKED(r));
1194 056fe1ba 2003-11-23 devnull if(offset == 0)
1195 056fe1ba 2003-11-23 devnull return 0;
1197 056fe1ba 2003-11-23 devnull b = fileload(r, &e);
1198 056fe1ba 2003-11-23 devnull if(b == nil)
1199 056fe1ba 2003-11-23 devnull return -1;
1201 056fe1ba 2003-11-23 devnull ret = -1;
1202 056fe1ba 2003-11-23 devnull memset(bi, 0, sizeof bi);
1203 056fe1ba 2003-11-23 devnull depth = DEPTH(e.type);
1204 056fe1ba 2003-11-23 devnull bi[depth+1] = b;
1205 056fe1ba 2003-11-23 devnull i = mkindices(&e, (offset-1)/e.dsize, index);
1206 056fe1ba 2003-11-23 devnull if(i < 0)
1207 056fe1ba 2003-11-23 devnull goto Err;
1208 056fe1ba 2003-11-23 devnull if(i > depth)
1209 056fe1ba 2003-11-23 devnull goto Err;
1210 056fe1ba 2003-11-23 devnull mkindices(&e, offset/e.dsize, index1);
1211 056fe1ba 2003-11-23 devnull ppb = e.psize / VtScoreSize;
1212 056fe1ba 2003-11-23 devnull epb = e.dsize / VtEntrySize;
1214 056fe1ba 2003-11-23 devnull index[depth] = r->offset % r->epb;
1215 056fe1ba 2003-11-23 devnull for(i=depth; i>=0; i--){
1216 056fe1ba 2003-11-23 devnull bb = blockwalk(b, index[i], r->c, VtORDWR, &e);
1217 056fe1ba 2003-11-23 devnull if(bb == nil)
1218 056fe1ba 2003-11-23 devnull goto Err;
1219 056fe1ba 2003-11-23 devnull bi[i] = bb;
1220 056fe1ba 2003-11-23 devnull b = bb;
1222 056fe1ba 2003-11-23 devnull ret = 0;
1224 056fe1ba 2003-11-23 devnull base = e.type&~VtTypeDepthMask;
1225 056fe1ba 2003-11-23 devnull for(i=0; i<depth; i++){
1226 056fe1ba 2003-11-23 devnull if(i == 0){
1227 056fe1ba 2003-11-23 devnull /* bottom: data or dir block */
1228 056fe1ba 2003-11-23 devnull ok = offset%e.dsize == 0;
1230 056fe1ba 2003-11-23 devnull /* middle: pointer blocks */
1231 056fe1ba 2003-11-23 devnull b = bi[i];
1233 056fe1ba 2003-11-23 devnull * flush everything up to the break
1235 056fe1ba 2003-11-23 devnull for(j=0; j<index[i-1]; j++)
1236 056fe1ba 2003-11-23 devnull if(flushblock(r->c, nil, b->data+j*VtScoreSize, ppb, epb, base+i-1) < 0)
1237 056fe1ba 2003-11-23 devnull goto Err;
1239 056fe1ba 2003-11-23 devnull * if the rest of the block is already flushed,
1240 056fe1ba 2003-11-23 devnull * we can flush the whole block.
1242 056fe1ba 2003-11-23 devnull ok = 1;
1243 056fe1ba 2003-11-23 devnull for(; j<ppb; j++)
1244 056fe1ba 2003-11-23 devnull if(vtglobaltolocal(b->data+j*VtScoreSize) != NilBlock)
1245 056fe1ba 2003-11-23 devnull ok = 0;
1247 056fe1ba 2003-11-23 devnull if(ok){
1248 056fe1ba 2003-11-23 devnull if(i == depth)
1249 056fe1ba 2003-11-23 devnull score = e.score;
1251 056fe1ba 2003-11-23 devnull score = bi[i+1]->data+index[i]*VtScoreSize;
1252 056fe1ba 2003-11-23 devnull if(flushblock(r->c, bi[i], score, ppb, epb, base+i) < 0)
1253 056fe1ba 2003-11-23 devnull goto Err;
1258 056fe1ba 2003-11-23 devnull /* top: entry. do this always so that the score is up-to-date */
1259 056fe1ba 2003-11-23 devnull vtentrypack(&e, bi[depth+1]->data, index[depth]);
1260 056fe1ba 2003-11-23 devnull for(i=0; i<nelem(bi); i++)
1261 056fe1ba 2003-11-23 devnull if(bi[i])
1262 056fe1ba 2003-11-23 devnull vtblockput(bi[i]);
1263 056fe1ba 2003-11-23 devnull return ret;