1368c31abSDavid du Colombier /*
2368c31abSDavid du Colombier * Manage tree of VtFiles stored in the block cache.
3368c31abSDavid du Colombier *
4368c31abSDavid du Colombier * The single point of truth for the info about the VtFiles themselves
5368c31abSDavid du Colombier * is the block data. Because of this, there is no explicit locking of
6368c31abSDavid du Colombier * VtFile structures, and indeed there may be more than one VtFile
7368c31abSDavid du Colombier * structure for a given Venti file. They synchronize through the
8368c31abSDavid du Colombier * block cache.
9368c31abSDavid du Colombier *
10368c31abSDavid du Colombier * This is a bit simpler than fossil because there are no epochs
11368c31abSDavid du Colombier * or tags or anything else. Just mutable local blocks and immutable
12368c31abSDavid du Colombier * Venti blocks.
13368c31abSDavid du Colombier */
14368c31abSDavid du Colombier
15368c31abSDavid du Colombier #include <u.h>
16368c31abSDavid du Colombier #include <libc.h>
17368c31abSDavid du Colombier #include <venti.h>
18368c31abSDavid du Colombier
19368c31abSDavid du Colombier #define MaxBlock (1UL<<31)
20368c31abSDavid du Colombier
21368c31abSDavid du Colombier static char ENotDir[] = "walk in non-directory";
22368c31abSDavid du Colombier static char ETooBig[] = "file too big";
23368c31abSDavid du Colombier /* static char EBadAddr[] = "bad address"; */
24368c31abSDavid du Colombier static char ELabelMismatch[] = "label mismatch";
25368c31abSDavid du Colombier
26368c31abSDavid du Colombier static int sizetodepth(uvlong s, int psize, int dsize);
27368c31abSDavid du Colombier static VtBlock *fileload(VtFile *r, VtEntry *e);
28368c31abSDavid du Colombier static int shrinkdepth(VtFile*, VtBlock*, VtEntry*, int);
29368c31abSDavid du Colombier static int shrinksize(VtFile*, VtEntry*, uvlong);
30368c31abSDavid du Colombier static int growdepth(VtFile*, VtBlock*, VtEntry*, int);
31368c31abSDavid du Colombier
32368c31abSDavid du Colombier #define ISLOCKED(r) ((r)->b != nil)
33368c31abSDavid du Colombier #define DEPTH(t) ((t)&VtTypeDepthMask)
34368c31abSDavid du Colombier
35368c31abSDavid du Colombier static VtFile *
vtfilealloc(VtCache * c,VtBlock * b,VtFile * p,u32int offset,int mode)36368c31abSDavid du Colombier vtfilealloc(VtCache *c, VtBlock *b, VtFile *p, u32int offset, int mode)
37368c31abSDavid du Colombier {
38368c31abSDavid du Colombier int epb;
39368c31abSDavid du Colombier u32int size;
40368c31abSDavid du Colombier VtEntry e;
41368c31abSDavid du Colombier VtFile *r;
42368c31abSDavid du Colombier
43368c31abSDavid du Colombier assert(p==nil || ISLOCKED(p));
44368c31abSDavid du Colombier
45368c31abSDavid du Colombier if(p == nil){
46368c31abSDavid du Colombier assert(offset == 0);
47368c31abSDavid du Colombier epb = 1;
48368c31abSDavid du Colombier }else
49368c31abSDavid du Colombier epb = p->dsize / VtEntrySize;
50368c31abSDavid du Colombier
51368c31abSDavid du Colombier if(b->type != VtDirType){
52368c31abSDavid du Colombier werrstr("bad block type %#uo", b->type);
53368c31abSDavid du Colombier return nil;
54368c31abSDavid du Colombier }
55368c31abSDavid du Colombier
56368c31abSDavid du Colombier /*
57368c31abSDavid du Colombier * a non-active entry is the only thing that
58368c31abSDavid du Colombier * can legitimately happen here. all the others
59368c31abSDavid du Colombier * get prints.
60368c31abSDavid du Colombier */
61368c31abSDavid du Colombier if(vtentryunpack(&e, b->data, offset % epb) < 0){
62368c31abSDavid du Colombier fprint(2, "vtentryunpack failed: %r (%.*H)\n", VtEntrySize, b->data+VtEntrySize*(offset%epb));
63368c31abSDavid du Colombier return nil;
64368c31abSDavid du Colombier }
65368c31abSDavid du Colombier if(!(e.flags & VtEntryActive)){
66368c31abSDavid du Colombier werrstr("entry not active");
67368c31abSDavid du Colombier return nil;
68368c31abSDavid du Colombier }
69368c31abSDavid du Colombier
70368c31abSDavid du Colombier if(DEPTH(e.type) < sizetodepth(e.size, e.psize, e.dsize)){
71368c31abSDavid du Colombier fprint(2, "depth %ud size %llud psize %ud dsize %ud\n",
72368c31abSDavid du Colombier DEPTH(e.type), e.size, e.psize, e.dsize);
73368c31abSDavid du Colombier werrstr("bad depth");
74368c31abSDavid du Colombier return nil;
75368c31abSDavid du Colombier }
76368c31abSDavid du Colombier
77368c31abSDavid du Colombier size = vtcacheblocksize(c);
78368c31abSDavid du Colombier if(e.dsize > size || e.psize > size){
79368c31abSDavid du Colombier werrstr("block sizes %ud, %ud bigger than cache block size %ud",
80368c31abSDavid du Colombier e.psize, e.dsize, size);
81368c31abSDavid du Colombier return nil;
82368c31abSDavid du Colombier }
83368c31abSDavid du Colombier
84368c31abSDavid du Colombier r = vtmallocz(sizeof(VtFile));
85368c31abSDavid du Colombier r->c = c;
86368c31abSDavid du Colombier r->mode = mode;
87368c31abSDavid du Colombier r->dsize = e.dsize;
88368c31abSDavid du Colombier r->psize = e.psize;
89368c31abSDavid du Colombier r->gen = e.gen;
90368c31abSDavid du Colombier r->dir = (e.type & VtTypeBaseMask) == VtDirType;
91368c31abSDavid du Colombier r->ref = 1;
92368c31abSDavid du Colombier r->parent = p;
93368c31abSDavid du Colombier if(p){
94368c31abSDavid du Colombier qlock(&p->lk);
95368c31abSDavid du Colombier assert(mode == VtOREAD || p->mode == VtORDWR);
96368c31abSDavid du Colombier p->ref++;
97368c31abSDavid du Colombier qunlock(&p->lk);
98368c31abSDavid du Colombier }else{
99368c31abSDavid du Colombier assert(b->addr != NilBlock);
100368c31abSDavid du Colombier r->local = 1;
101368c31abSDavid du Colombier }
102368c31abSDavid du Colombier memmove(r->score, b->score, VtScoreSize);
103368c31abSDavid du Colombier r->offset = offset;
104368c31abSDavid du Colombier r->epb = epb;
105368c31abSDavid du Colombier
106368c31abSDavid du Colombier return r;
107368c31abSDavid du Colombier }
108368c31abSDavid du Colombier
109368c31abSDavid du Colombier VtFile *
vtfileroot(VtCache * c,u32int addr,int mode)110368c31abSDavid du Colombier vtfileroot(VtCache *c, u32int addr, int mode)
111368c31abSDavid du Colombier {
112368c31abSDavid du Colombier VtFile *r;
113368c31abSDavid du Colombier VtBlock *b;
114368c31abSDavid du Colombier
115368c31abSDavid du Colombier b = vtcachelocal(c, addr, VtDirType);
116368c31abSDavid du Colombier if(b == nil)
117368c31abSDavid du Colombier return nil;
118368c31abSDavid du Colombier r = vtfilealloc(c, b, nil, 0, mode);
119368c31abSDavid du Colombier vtblockput(b);
120368c31abSDavid du Colombier return r;
121368c31abSDavid du Colombier }
122368c31abSDavid du Colombier
123368c31abSDavid du Colombier VtFile*
vtfileopenroot(VtCache * c,VtEntry * e)124368c31abSDavid du Colombier vtfileopenroot(VtCache *c, VtEntry *e)
125368c31abSDavid du Colombier {
126368c31abSDavid du Colombier VtBlock *b;
127368c31abSDavid du Colombier VtFile *f;
128368c31abSDavid du Colombier
129368c31abSDavid du Colombier b = vtcacheallocblock(c, VtDirType);
130368c31abSDavid du Colombier if(b == nil)
131368c31abSDavid du Colombier return nil;
132368c31abSDavid du Colombier
133368c31abSDavid du Colombier vtentrypack(e, b->data, 0);
134368c31abSDavid du Colombier f = vtfilealloc(c, b, nil, 0, VtORDWR);
135368c31abSDavid du Colombier vtblockput(b);
136368c31abSDavid du Colombier return f;
137368c31abSDavid du Colombier }
138368c31abSDavid du Colombier
139368c31abSDavid du Colombier VtFile *
vtfilecreateroot(VtCache * c,int psize,int dsize,int type)140368c31abSDavid du Colombier vtfilecreateroot(VtCache *c, int psize, int dsize, int type)
141368c31abSDavid du Colombier {
142368c31abSDavid du Colombier VtEntry e;
143368c31abSDavid du Colombier
144368c31abSDavid du Colombier memset(&e, 0, sizeof e);
145368c31abSDavid du Colombier e.flags = VtEntryActive;
146368c31abSDavid du Colombier e.psize = psize;
147368c31abSDavid du Colombier e.dsize = dsize;
148368c31abSDavid du Colombier e.type = type;
149368c31abSDavid du Colombier memmove(e.score, vtzeroscore, VtScoreSize);
150368c31abSDavid du Colombier
151368c31abSDavid du Colombier return vtfileopenroot(c, &e);
152368c31abSDavid du Colombier }
153368c31abSDavid du Colombier
154368c31abSDavid du Colombier VtFile *
vtfileopen(VtFile * r,u32int offset,int mode)155368c31abSDavid du Colombier vtfileopen(VtFile *r, u32int offset, int mode)
156368c31abSDavid du Colombier {
157368c31abSDavid du Colombier ulong bn;
158368c31abSDavid du Colombier VtBlock *b;
159368c31abSDavid du Colombier
160368c31abSDavid du Colombier assert(ISLOCKED(r));
161368c31abSDavid du Colombier if(!r->dir){
162368c31abSDavid du Colombier werrstr(ENotDir);
163368c31abSDavid du Colombier return nil;
164368c31abSDavid du Colombier }
165368c31abSDavid du Colombier
166368c31abSDavid du Colombier bn = offset/(r->dsize/VtEntrySize);
167368c31abSDavid du Colombier
168368c31abSDavid du Colombier b = vtfileblock(r, bn, mode);
169368c31abSDavid du Colombier if(b == nil)
170368c31abSDavid du Colombier return nil;
171368c31abSDavid du Colombier r = vtfilealloc(r->c, b, r, offset, mode);
172368c31abSDavid du Colombier vtblockput(b);
173368c31abSDavid du Colombier return r;
174368c31abSDavid du Colombier }
175368c31abSDavid du Colombier
176368c31abSDavid du Colombier VtFile*
vtfilecreate(VtFile * r,int psize,int dsize,int type)177368c31abSDavid du Colombier vtfilecreate(VtFile *r, int psize, int dsize, int type)
178368c31abSDavid du Colombier {
179368c31abSDavid du Colombier return _vtfilecreate(r, -1, psize, dsize, type);
180368c31abSDavid du Colombier }
181368c31abSDavid du Colombier
182368c31abSDavid du Colombier VtFile*
_vtfilecreate(VtFile * r,int o,int psize,int dsize,int type)183368c31abSDavid du Colombier _vtfilecreate(VtFile *r, int o, int psize, int dsize, int type)
184368c31abSDavid du Colombier {
185368c31abSDavid du Colombier int i;
186368c31abSDavid du Colombier VtBlock *b;
187368c31abSDavid du Colombier u32int bn, size;
188368c31abSDavid du Colombier VtEntry e;
189368c31abSDavid du Colombier int epb;
190368c31abSDavid du Colombier VtFile *rr;
191368c31abSDavid du Colombier u32int offset;
192368c31abSDavid du Colombier
193368c31abSDavid du Colombier assert(ISLOCKED(r));
194368c31abSDavid du Colombier assert(psize <= VtMaxLumpSize);
195368c31abSDavid du Colombier assert(dsize <= VtMaxLumpSize);
196368c31abSDavid du Colombier assert(type == VtDirType || type == VtDataType);
197368c31abSDavid du Colombier
198368c31abSDavid du Colombier if(!r->dir){
199368c31abSDavid du Colombier werrstr(ENotDir);
200368c31abSDavid du Colombier return nil;
201368c31abSDavid du Colombier }
202368c31abSDavid du Colombier
203368c31abSDavid du Colombier epb = r->dsize/VtEntrySize;
204368c31abSDavid du Colombier
205368c31abSDavid du Colombier size = vtfilegetdirsize(r);
206368c31abSDavid du Colombier /*
207368c31abSDavid du Colombier * look at a random block to see if we can find an empty entry
208368c31abSDavid du Colombier */
209368c31abSDavid du Colombier if(o == -1){
210368c31abSDavid du Colombier offset = lnrand(size+1);
211368c31abSDavid du Colombier offset -= offset % epb;
212368c31abSDavid du Colombier }else
213368c31abSDavid du Colombier offset = o;
214368c31abSDavid du Colombier
215368c31abSDavid du Colombier /* try the given block and then try the last block */
216368c31abSDavid du Colombier for(;;){
217368c31abSDavid du Colombier bn = offset/epb;
218368c31abSDavid du Colombier b = vtfileblock(r, bn, VtORDWR);
219368c31abSDavid du Colombier if(b == nil)
220368c31abSDavid du Colombier return nil;
221368c31abSDavid du Colombier for(i=offset%r->epb; i<epb; i++){
222368c31abSDavid du Colombier if(vtentryunpack(&e, b->data, i) < 0)
223368c31abSDavid du Colombier continue;
224368c31abSDavid du Colombier if((e.flags&VtEntryActive) == 0 && e.gen != ~0)
225368c31abSDavid du Colombier goto Found;
226368c31abSDavid du Colombier }
227368c31abSDavid du Colombier vtblockput(b);
228368c31abSDavid du Colombier if(offset == size){
229368c31abSDavid du Colombier fprint(2, "vtfilecreate: cannot happen\n");
230368c31abSDavid du Colombier werrstr("vtfilecreate: cannot happen");
231368c31abSDavid du Colombier return nil;
232368c31abSDavid du Colombier }
233368c31abSDavid du Colombier offset = size;
234368c31abSDavid du Colombier }
235368c31abSDavid du Colombier
236368c31abSDavid du Colombier Found:
237368c31abSDavid du Colombier /* found an entry - gen already set */
238368c31abSDavid du Colombier e.psize = psize;
239368c31abSDavid du Colombier e.dsize = dsize;
240368c31abSDavid du Colombier e.flags = VtEntryActive;
241368c31abSDavid du Colombier e.type = type;
242368c31abSDavid du Colombier e.size = 0;
243368c31abSDavid du Colombier memmove(e.score, vtzeroscore, VtScoreSize);
244368c31abSDavid du Colombier vtentrypack(&e, b->data, i);
245368c31abSDavid du Colombier
246368c31abSDavid du Colombier offset = bn*epb + i;
247368c31abSDavid du Colombier if(offset+1 > size){
248368c31abSDavid du Colombier if(vtfilesetdirsize(r, offset+1) < 0){
249368c31abSDavid du Colombier vtblockput(b);
250368c31abSDavid du Colombier return nil;
251368c31abSDavid du Colombier }
252368c31abSDavid du Colombier }
253368c31abSDavid du Colombier
254368c31abSDavid du Colombier rr = vtfilealloc(r->c, b, r, offset, VtORDWR);
255368c31abSDavid du Colombier vtblockput(b);
256368c31abSDavid du Colombier return rr;
257368c31abSDavid du Colombier }
258368c31abSDavid du Colombier
259368c31abSDavid du Colombier static int
vtfilekill(VtFile * r,int doremove)260368c31abSDavid du Colombier vtfilekill(VtFile *r, int doremove)
261368c31abSDavid du Colombier {
262368c31abSDavid du Colombier VtEntry e;
263368c31abSDavid du Colombier VtBlock *b;
264368c31abSDavid du Colombier
265368c31abSDavid du Colombier assert(ISLOCKED(r));
266368c31abSDavid du Colombier b = fileload(r, &e);
267368c31abSDavid du Colombier if(b == nil)
268368c31abSDavid du Colombier return -1;
269368c31abSDavid du Colombier
270368c31abSDavid du Colombier if(doremove==0 && e.size == 0){
271368c31abSDavid du Colombier /* already truncated */
272368c31abSDavid du Colombier vtblockput(b);
273368c31abSDavid du Colombier return 0;
274368c31abSDavid du Colombier }
275368c31abSDavid du Colombier
276368c31abSDavid du Colombier if(doremove){
277368c31abSDavid du Colombier if(e.gen != ~0)
278368c31abSDavid du Colombier e.gen++;
279368c31abSDavid du Colombier e.dsize = 0;
280368c31abSDavid du Colombier e.psize = 0;
281368c31abSDavid du Colombier e.flags = 0;
282368c31abSDavid du Colombier }else
283368c31abSDavid du Colombier e.flags &= ~VtEntryLocal;
284368c31abSDavid du Colombier e.type = 0;
285368c31abSDavid du Colombier e.size = 0;
286368c31abSDavid du Colombier memmove(e.score, vtzeroscore, VtScoreSize);
287368c31abSDavid du Colombier vtentrypack(&e, b->data, r->offset % r->epb);
288368c31abSDavid du Colombier vtblockput(b);
289368c31abSDavid du Colombier
290368c31abSDavid du Colombier if(doremove){
291368c31abSDavid du Colombier vtfileunlock(r);
292368c31abSDavid du Colombier vtfileclose(r);
293368c31abSDavid du Colombier }
294368c31abSDavid du Colombier
295368c31abSDavid du Colombier return 0;
296368c31abSDavid du Colombier }
297368c31abSDavid du Colombier
298368c31abSDavid du Colombier int
vtfileremove(VtFile * r)299368c31abSDavid du Colombier vtfileremove(VtFile *r)
300368c31abSDavid du Colombier {
301368c31abSDavid du Colombier return vtfilekill(r, 1);
302368c31abSDavid du Colombier }
303368c31abSDavid du Colombier
304368c31abSDavid du Colombier int
vtfiletruncate(VtFile * r)305368c31abSDavid du Colombier vtfiletruncate(VtFile *r)
306368c31abSDavid du Colombier {
307368c31abSDavid du Colombier return vtfilekill(r, 0);
308368c31abSDavid du Colombier }
309368c31abSDavid du Colombier
310368c31abSDavid du Colombier uvlong
vtfilegetsize(VtFile * r)311368c31abSDavid du Colombier vtfilegetsize(VtFile *r)
312368c31abSDavid du Colombier {
313368c31abSDavid du Colombier VtEntry e;
314368c31abSDavid du Colombier VtBlock *b;
315368c31abSDavid du Colombier
316368c31abSDavid du Colombier assert(ISLOCKED(r));
317368c31abSDavid du Colombier b = fileload(r, &e);
318368c31abSDavid du Colombier if(b == nil)
319368c31abSDavid du Colombier return ~(uvlong)0;
320368c31abSDavid du Colombier vtblockput(b);
321368c31abSDavid du Colombier
322368c31abSDavid du Colombier return e.size;
323368c31abSDavid du Colombier }
324368c31abSDavid du Colombier
325368c31abSDavid du Colombier static int
shrinksize(VtFile * r,VtEntry * e,uvlong size)326368c31abSDavid du Colombier shrinksize(VtFile *r, VtEntry *e, uvlong size)
327368c31abSDavid du Colombier {
328368c31abSDavid du Colombier int i, depth, type, isdir, ppb;
329368c31abSDavid du Colombier uvlong ptrsz;
330368c31abSDavid du Colombier uchar score[VtScoreSize];
331368c31abSDavid du Colombier VtBlock *b;
332368c31abSDavid du Colombier
333368c31abSDavid du Colombier b = vtcacheglobal(r->c, e->score, e->type);
334368c31abSDavid du Colombier if(b == nil)
335368c31abSDavid du Colombier return -1;
336368c31abSDavid du Colombier
337368c31abSDavid du Colombier ptrsz = e->dsize;
338368c31abSDavid du Colombier ppb = e->psize/VtScoreSize;
339368c31abSDavid du Colombier type = e->type;
340368c31abSDavid du Colombier depth = DEPTH(type);
341368c31abSDavid du Colombier for(i=0; i+1<depth; i++)
342368c31abSDavid du Colombier ptrsz *= ppb;
343368c31abSDavid du Colombier
344368c31abSDavid du Colombier isdir = r->dir;
345368c31abSDavid du Colombier while(depth > 0){
346368c31abSDavid du Colombier if(b->addr == NilBlock){
347368c31abSDavid du Colombier /* not worth copying the block just so we can zero some of it */
348368c31abSDavid du Colombier vtblockput(b);
349368c31abSDavid du Colombier return -1;
350368c31abSDavid du Colombier }
351368c31abSDavid du Colombier
352368c31abSDavid du Colombier /*
353368c31abSDavid du Colombier * invariant: each pointer in the tree rooted at b accounts for ptrsz bytes
354368c31abSDavid du Colombier */
355368c31abSDavid du Colombier
356368c31abSDavid du Colombier /* zero the pointers to unnecessary blocks */
357368c31abSDavid du Colombier i = (size+ptrsz-1)/ptrsz;
358368c31abSDavid du Colombier for(; i<ppb; i++)
359368c31abSDavid du Colombier memmove(b->data+i*VtScoreSize, vtzeroscore, VtScoreSize);
360368c31abSDavid du Colombier
361368c31abSDavid du Colombier /* recurse (go around again) on the partially necessary block */
362368c31abSDavid du Colombier i = size/ptrsz;
363368c31abSDavid du Colombier size = size%ptrsz;
364368c31abSDavid du Colombier if(size == 0){
365368c31abSDavid du Colombier vtblockput(b);
366368c31abSDavid du Colombier return 0;
367368c31abSDavid du Colombier }
368368c31abSDavid du Colombier ptrsz /= ppb;
369368c31abSDavid du Colombier type--;
370368c31abSDavid du Colombier memmove(score, b->data+i*VtScoreSize, VtScoreSize);
371368c31abSDavid du Colombier vtblockput(b);
372368c31abSDavid du Colombier b = vtcacheglobal(r->c, score, type);
373368c31abSDavid du Colombier if(b == nil)
374368c31abSDavid du Colombier return -1;
375368c31abSDavid du Colombier }
376368c31abSDavid du Colombier
377368c31abSDavid du Colombier if(b->addr == NilBlock){
378368c31abSDavid du Colombier vtblockput(b);
379368c31abSDavid du Colombier return -1;
380368c31abSDavid du Colombier }
381368c31abSDavid du Colombier
382368c31abSDavid du Colombier /*
383368c31abSDavid du Colombier * No one ever truncates BtDir blocks.
384368c31abSDavid du Colombier */
385368c31abSDavid du Colombier if(depth==0 && !isdir && e->dsize > size)
386368c31abSDavid du Colombier memset(b->data+size, 0, e->dsize-size);
387368c31abSDavid du Colombier vtblockput(b);
388368c31abSDavid du Colombier return 0;
389368c31abSDavid du Colombier }
390368c31abSDavid du Colombier
391368c31abSDavid du Colombier int
vtfilesetsize(VtFile * r,u64int size)392368c31abSDavid du Colombier vtfilesetsize(VtFile *r, u64int size)
393368c31abSDavid du Colombier {
394368c31abSDavid du Colombier int depth, edepth;
395368c31abSDavid du Colombier VtEntry e;
396368c31abSDavid du Colombier VtBlock *b;
397368c31abSDavid du Colombier
398368c31abSDavid du Colombier assert(ISLOCKED(r));
399368c31abSDavid du Colombier if(size == 0)
400368c31abSDavid du Colombier return vtfiletruncate(r);
401368c31abSDavid du Colombier
402368c31abSDavid du Colombier if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize){
403368c31abSDavid du Colombier werrstr(ETooBig);
404368c31abSDavid du Colombier return -1;
405368c31abSDavid du Colombier }
406368c31abSDavid du Colombier
407368c31abSDavid du Colombier b = fileload(r, &e);
408368c31abSDavid du Colombier if(b == nil)
409368c31abSDavid du Colombier return -1;
410368c31abSDavid du Colombier
411368c31abSDavid du Colombier /* quick out */
412368c31abSDavid du Colombier if(e.size == size){
413368c31abSDavid du Colombier vtblockput(b);
414368c31abSDavid du Colombier return 0;
415368c31abSDavid du Colombier }
416368c31abSDavid du Colombier
417368c31abSDavid du Colombier depth = sizetodepth(size, e.psize, e.dsize);
418368c31abSDavid du Colombier edepth = DEPTH(e.type);
419368c31abSDavid du Colombier if(depth < edepth){
420368c31abSDavid du Colombier if(shrinkdepth(r, b, &e, depth) < 0){
421368c31abSDavid du Colombier vtblockput(b);
422368c31abSDavid du Colombier return -1;
423368c31abSDavid du Colombier }
424368c31abSDavid du Colombier }else if(depth > edepth){
425368c31abSDavid du Colombier if(growdepth(r, b, &e, depth) < 0){
426368c31abSDavid du Colombier vtblockput(b);
427368c31abSDavid du Colombier return -1;
428368c31abSDavid du Colombier }
429368c31abSDavid du Colombier }
430368c31abSDavid du Colombier
431368c31abSDavid du Colombier if(size < e.size)
432368c31abSDavid du Colombier shrinksize(r, &e, size);
433368c31abSDavid du Colombier
434368c31abSDavid du Colombier e.size = size;
435368c31abSDavid du Colombier vtentrypack(&e, b->data, r->offset % r->epb);
436368c31abSDavid du Colombier vtblockput(b);
437368c31abSDavid du Colombier
438368c31abSDavid du Colombier return 0;
439368c31abSDavid du Colombier }
440368c31abSDavid du Colombier
441368c31abSDavid du Colombier int
vtfilesetdirsize(VtFile * r,u32int ds)442368c31abSDavid du Colombier vtfilesetdirsize(VtFile *r, u32int ds)
443368c31abSDavid du Colombier {
444368c31abSDavid du Colombier uvlong size;
445368c31abSDavid du Colombier int epb;
446368c31abSDavid du Colombier
447368c31abSDavid du Colombier assert(ISLOCKED(r));
448368c31abSDavid du Colombier epb = r->dsize/VtEntrySize;
449368c31abSDavid du Colombier
450368c31abSDavid du Colombier size = (uvlong)r->dsize*(ds/epb);
451368c31abSDavid du Colombier size += VtEntrySize*(ds%epb);
452368c31abSDavid du Colombier return vtfilesetsize(r, size);
453368c31abSDavid du Colombier }
454368c31abSDavid du Colombier
455368c31abSDavid du Colombier u32int
vtfilegetdirsize(VtFile * r)456368c31abSDavid du Colombier vtfilegetdirsize(VtFile *r)
457368c31abSDavid du Colombier {
458368c31abSDavid du Colombier ulong ds;
459368c31abSDavid du Colombier uvlong size;
460368c31abSDavid du Colombier int epb;
461368c31abSDavid du Colombier
462368c31abSDavid du Colombier assert(ISLOCKED(r));
463368c31abSDavid du Colombier epb = r->dsize/VtEntrySize;
464368c31abSDavid du Colombier
465368c31abSDavid du Colombier size = vtfilegetsize(r);
466368c31abSDavid du Colombier ds = epb*(size/r->dsize);
467368c31abSDavid du Colombier ds += (size%r->dsize)/VtEntrySize;
468368c31abSDavid du Colombier return ds;
469368c31abSDavid du Colombier }
470368c31abSDavid du Colombier
471368c31abSDavid du Colombier int
vtfilegetentry(VtFile * r,VtEntry * e)472368c31abSDavid du Colombier vtfilegetentry(VtFile *r, VtEntry *e)
473368c31abSDavid du Colombier {
474368c31abSDavid du Colombier VtBlock *b;
475368c31abSDavid du Colombier
476368c31abSDavid du Colombier assert(ISLOCKED(r));
477368c31abSDavid du Colombier b = fileload(r, e);
478368c31abSDavid du Colombier if(b == nil)
479368c31abSDavid du Colombier return -1;
480368c31abSDavid du Colombier vtblockput(b);
481368c31abSDavid du Colombier
482368c31abSDavid du Colombier return 0;
483368c31abSDavid du Colombier }
484368c31abSDavid du Colombier
485368c31abSDavid du Colombier int
vtfilesetentry(VtFile * r,VtEntry * e)486368c31abSDavid du Colombier vtfilesetentry(VtFile *r, VtEntry *e)
487368c31abSDavid du Colombier {
488368c31abSDavid du Colombier VtBlock *b;
489368c31abSDavid du Colombier VtEntry ee;
490368c31abSDavid du Colombier
491368c31abSDavid du Colombier assert(ISLOCKED(r));
492368c31abSDavid du Colombier b = fileload(r, &ee);
493368c31abSDavid du Colombier if(b == nil)
494368c31abSDavid du Colombier return -1;
495368c31abSDavid du Colombier vtentrypack(e, b->data, r->offset % r->epb);
496368c31abSDavid du Colombier vtblockput(b);
497368c31abSDavid du Colombier return 0;
498368c31abSDavid du Colombier }
499368c31abSDavid du Colombier
500368c31abSDavid du Colombier static VtBlock *
blockwalk(VtBlock * p,int index,VtCache * c,int mode,VtEntry * e)501368c31abSDavid du Colombier blockwalk(VtBlock *p, int index, VtCache *c, int mode, VtEntry *e)
502368c31abSDavid du Colombier {
503368c31abSDavid du Colombier VtBlock *b;
504368c31abSDavid du Colombier int type;
505368c31abSDavid du Colombier uchar *score;
506368c31abSDavid du Colombier VtEntry oe;
507368c31abSDavid du Colombier
508368c31abSDavid du Colombier switch(p->type){
509368c31abSDavid du Colombier case VtDataType:
510368c31abSDavid du Colombier assert(0);
511368c31abSDavid du Colombier case VtDirType:
512368c31abSDavid du Colombier type = e->type;
513368c31abSDavid du Colombier score = e->score;
514368c31abSDavid du Colombier break;
515368c31abSDavid du Colombier default:
516368c31abSDavid du Colombier type = p->type - 1;
517368c31abSDavid du Colombier score = p->data+index*VtScoreSize;
518368c31abSDavid du Colombier break;
519368c31abSDavid du Colombier }
520368c31abSDavid du Colombier /*print("walk from %V/%d ty %d to %V ty %d\n", p->score, index, p->type, score, type); */
521368c31abSDavid du Colombier
522368c31abSDavid du Colombier if(mode == VtOWRITE && vtglobaltolocal(score) == NilBlock){
523368c31abSDavid du Colombier b = vtcacheallocblock(c, type);
524368c31abSDavid du Colombier if(b)
525368c31abSDavid du Colombier goto HaveCopy;
526368c31abSDavid du Colombier }else
527368c31abSDavid du Colombier b = vtcacheglobal(c, score, type);
528368c31abSDavid du Colombier
529368c31abSDavid du Colombier if(b == nil || mode == VtOREAD)
530368c31abSDavid du Colombier return b;
531368c31abSDavid du Colombier
532368c31abSDavid du Colombier if(vtglobaltolocal(b->score) != NilBlock)
533368c31abSDavid du Colombier return b;
534368c31abSDavid du Colombier
535368c31abSDavid du Colombier oe = *e;
536368c31abSDavid du Colombier
537368c31abSDavid du Colombier /*
538368c31abSDavid du Colombier * Copy on write.
539368c31abSDavid du Colombier */
540368c31abSDavid du Colombier e->flags |= VtEntryLocal;
541368c31abSDavid du Colombier
542368c31abSDavid du Colombier b = vtblockcopy(b/*, e->tag, fs->ehi, fs->elo*/);
543368c31abSDavid du Colombier if(b == nil)
544368c31abSDavid du Colombier return nil;
545368c31abSDavid du Colombier
546368c31abSDavid du Colombier HaveCopy:
547368c31abSDavid du Colombier if(p->type == VtDirType){
548368c31abSDavid du Colombier memmove(e->score, b->score, VtScoreSize);
549368c31abSDavid du Colombier vtentrypack(e, p->data, index);
550368c31abSDavid du Colombier }else{
551368c31abSDavid du Colombier memmove(p->data+index*VtScoreSize, b->score, VtScoreSize);
552368c31abSDavid du Colombier }
553368c31abSDavid du Colombier return b;
554368c31abSDavid du Colombier }
555368c31abSDavid du Colombier
556368c31abSDavid du Colombier /*
557368c31abSDavid du Colombier * Change the depth of the VtFile r.
558368c31abSDavid du Colombier * The entry e for r is contained in block p.
559368c31abSDavid du Colombier */
560368c31abSDavid du Colombier static int
growdepth(VtFile * r,VtBlock * p,VtEntry * e,int depth)561368c31abSDavid du Colombier growdepth(VtFile *r, VtBlock *p, VtEntry *e, int depth)
562368c31abSDavid du Colombier {
563368c31abSDavid du Colombier VtBlock *b, *bb;
564368c31abSDavid du Colombier VtEntry oe;
565368c31abSDavid du Colombier
566368c31abSDavid du Colombier assert(ISLOCKED(r));
567368c31abSDavid du Colombier assert(depth <= VtPointerDepth);
568368c31abSDavid du Colombier
569368c31abSDavid du Colombier b = vtcacheglobal(r->c, e->score, e->type);
570368c31abSDavid du Colombier if(b == nil)
571368c31abSDavid du Colombier return -1;
572368c31abSDavid du Colombier
573368c31abSDavid du Colombier oe = *e;
574368c31abSDavid du Colombier
575368c31abSDavid du Colombier /*
576368c31abSDavid du Colombier * Keep adding layers until we get to the right depth
577368c31abSDavid du Colombier * or an error occurs.
578368c31abSDavid du Colombier */
579368c31abSDavid du Colombier while(DEPTH(e->type) < depth){
580368c31abSDavid du Colombier bb = vtcacheallocblock(r->c, e->type+1);
581368c31abSDavid du Colombier if(bb == nil)
582368c31abSDavid du Colombier break;
583368c31abSDavid du Colombier memmove(bb->data, b->score, VtScoreSize);
584368c31abSDavid du Colombier memmove(e->score, bb->score, VtScoreSize);
585368c31abSDavid du Colombier e->type++;
586368c31abSDavid du Colombier e->flags |= VtEntryLocal;
587368c31abSDavid du Colombier vtblockput(b);
588368c31abSDavid du Colombier b = bb;
589368c31abSDavid du Colombier }
590368c31abSDavid du Colombier
591368c31abSDavid du Colombier vtentrypack(e, p->data, r->offset % r->epb);
592368c31abSDavid du Colombier vtblockput(b);
593368c31abSDavid du Colombier
594368c31abSDavid du Colombier if(DEPTH(e->type) == depth)
595368c31abSDavid du Colombier return 0;
596368c31abSDavid du Colombier return -1;
597368c31abSDavid du Colombier }
598368c31abSDavid du Colombier
599368c31abSDavid du Colombier static int
shrinkdepth(VtFile * r,VtBlock * p,VtEntry * e,int depth)600368c31abSDavid du Colombier shrinkdepth(VtFile *r, VtBlock *p, VtEntry *e, int depth)
601368c31abSDavid du Colombier {
602368c31abSDavid du Colombier VtBlock *b, *nb, *ob, *rb;
603368c31abSDavid du Colombier VtEntry oe;
604368c31abSDavid du Colombier
605368c31abSDavid du Colombier assert(ISLOCKED(r));
606368c31abSDavid du Colombier assert(depth <= VtPointerDepth);
607368c31abSDavid du Colombier
608368c31abSDavid du Colombier rb = vtcacheglobal(r->c, e->score, e->type);
609368c31abSDavid du Colombier if(rb == nil)
610*9ba92a1aSDavid du Colombier return -1;
611368c31abSDavid du Colombier
612368c31abSDavid du Colombier /*
613368c31abSDavid du Colombier * Walk down to the new root block.
614368c31abSDavid du Colombier * We may stop early, but something is better than nothing.
615368c31abSDavid du Colombier */
616368c31abSDavid du Colombier oe = *e;
617368c31abSDavid du Colombier
618368c31abSDavid du Colombier ob = nil;
619368c31abSDavid du Colombier b = rb;
620368c31abSDavid du Colombier for(; DEPTH(e->type) > depth; e->type--){
621368c31abSDavid du Colombier nb = vtcacheglobal(r->c, b->data, e->type-1);
622368c31abSDavid du Colombier if(nb == nil)
623368c31abSDavid du Colombier break;
624368c31abSDavid du Colombier if(ob!=nil && ob!=rb)
625368c31abSDavid du Colombier vtblockput(ob);
626368c31abSDavid du Colombier ob = b;
627368c31abSDavid du Colombier b = nb;
628368c31abSDavid du Colombier }
629368c31abSDavid du Colombier
630368c31abSDavid du Colombier if(b == rb){
631368c31abSDavid du Colombier vtblockput(rb);
632368c31abSDavid du Colombier return 0;
633368c31abSDavid du Colombier }
634368c31abSDavid du Colombier
635368c31abSDavid du Colombier /*
636368c31abSDavid du Colombier * Right now, e points at the root block rb, b is the new root block,
637368c31abSDavid du Colombier * and ob points at b. To update:
638368c31abSDavid du Colombier *
639368c31abSDavid du Colombier * (i) change e to point at b
640368c31abSDavid du Colombier * (ii) zero the pointer ob -> b
641368c31abSDavid du Colombier * (iii) free the root block
642368c31abSDavid du Colombier *
643368c31abSDavid du Colombier * p (the block containing e) must be written before
644368c31abSDavid du Colombier * anything else.
645368c31abSDavid du Colombier */
646368c31abSDavid du Colombier
647368c31abSDavid du Colombier /* (i) */
648368c31abSDavid du Colombier memmove(e->score, b->score, VtScoreSize);
649368c31abSDavid du Colombier vtentrypack(e, p->data, r->offset % r->epb);
650368c31abSDavid du Colombier
651368c31abSDavid du Colombier /* (ii) */
652368c31abSDavid du Colombier memmove(ob->data, vtzeroscore, VtScoreSize);
653368c31abSDavid du Colombier
654368c31abSDavid du Colombier /* (iii) */
655368c31abSDavid du Colombier vtblockput(rb);
656368c31abSDavid du Colombier if(ob!=nil && ob!=rb)
657368c31abSDavid du Colombier vtblockput(ob);
658368c31abSDavid du Colombier vtblockput(b);
659368c31abSDavid du Colombier
660368c31abSDavid du Colombier if(DEPTH(e->type) == depth)
661368c31abSDavid du Colombier return 0;
662368c31abSDavid du Colombier return -1;
663368c31abSDavid du Colombier }
664368c31abSDavid du Colombier
665368c31abSDavid du Colombier static int
mkindices(VtEntry * e,u32int bn,int * index)666368c31abSDavid du Colombier mkindices(VtEntry *e, u32int bn, int *index)
667368c31abSDavid du Colombier {
668368c31abSDavid du Colombier int i, np;
669368c31abSDavid du Colombier
670368c31abSDavid du Colombier memset(index, 0, (VtPointerDepth+1)*sizeof(int));
671368c31abSDavid du Colombier
672368c31abSDavid du Colombier np = e->psize/VtScoreSize;
673368c31abSDavid du Colombier for(i=0; bn > 0; i++){
674368c31abSDavid du Colombier if(i >= VtPointerDepth){
675368c31abSDavid du Colombier werrstr("bad address 0x%lux", (ulong)bn);
676368c31abSDavid du Colombier return -1;
677368c31abSDavid du Colombier }
678368c31abSDavid du Colombier index[i] = bn % np;
679368c31abSDavid du Colombier bn /= np;
680368c31abSDavid du Colombier }
681368c31abSDavid du Colombier return i;
682368c31abSDavid du Colombier }
683368c31abSDavid du Colombier
684368c31abSDavid du Colombier VtBlock *
vtfileblock(VtFile * r,u32int bn,int mode)685368c31abSDavid du Colombier vtfileblock(VtFile *r, u32int bn, int mode)
686368c31abSDavid du Colombier {
687368c31abSDavid du Colombier VtBlock *b, *bb;
688368c31abSDavid du Colombier int index[VtPointerDepth+1];
689368c31abSDavid du Colombier VtEntry e;
690368c31abSDavid du Colombier int i;
691368c31abSDavid du Colombier int m;
692368c31abSDavid du Colombier
693368c31abSDavid du Colombier assert(ISLOCKED(r));
694368c31abSDavid du Colombier assert(bn != NilBlock);
695368c31abSDavid du Colombier
696368c31abSDavid du Colombier b = fileload(r, &e);
697368c31abSDavid du Colombier if(b == nil)
698368c31abSDavid du Colombier return nil;
699368c31abSDavid du Colombier
700368c31abSDavid du Colombier i = mkindices(&e, bn, index);
701368c31abSDavid du Colombier if(i < 0)
702368c31abSDavid du Colombier goto Err;
703368c31abSDavid du Colombier if(i > DEPTH(e.type)){
704368c31abSDavid du Colombier if(mode == VtOREAD){
705368c31abSDavid du Colombier werrstr("bad address 0x%lux", (ulong)bn);
706368c31abSDavid du Colombier goto Err;
707368c31abSDavid du Colombier }
708368c31abSDavid du Colombier index[i] = 0;
709368c31abSDavid du Colombier if(growdepth(r, b, &e, i) < 0)
710368c31abSDavid du Colombier goto Err;
711368c31abSDavid du Colombier }
712368c31abSDavid du Colombier
713368c31abSDavid du Colombier assert(b->type == VtDirType);
714368c31abSDavid du Colombier
715368c31abSDavid du Colombier index[DEPTH(e.type)] = r->offset % r->epb;
716368c31abSDavid du Colombier
717368c31abSDavid du Colombier /* mode for intermediate block */
718368c31abSDavid du Colombier m = mode;
719368c31abSDavid du Colombier if(m == VtOWRITE)
720368c31abSDavid du Colombier m = VtORDWR;
721368c31abSDavid du Colombier
722368c31abSDavid du Colombier for(i=DEPTH(e.type); i>=0; i--){
723368c31abSDavid du Colombier bb = blockwalk(b, index[i], r->c, i==0 ? mode : m, &e);
724368c31abSDavid du Colombier if(bb == nil)
725368c31abSDavid du Colombier goto Err;
726368c31abSDavid du Colombier vtblockput(b);
727368c31abSDavid du Colombier b = bb;
728368c31abSDavid du Colombier }
729368c31abSDavid du Colombier b->pc = getcallerpc(&r);
730368c31abSDavid du Colombier return b;
731368c31abSDavid du Colombier Err:
732368c31abSDavid du Colombier vtblockput(b);
733368c31abSDavid du Colombier return nil;
734368c31abSDavid du Colombier }
735368c31abSDavid du Colombier
736368c31abSDavid du Colombier int
vtfileblockscore(VtFile * r,u32int bn,uchar score[VtScoreSize])737368c31abSDavid du Colombier vtfileblockscore(VtFile *r, u32int bn, uchar score[VtScoreSize])
738368c31abSDavid du Colombier {
739368c31abSDavid du Colombier VtBlock *b, *bb;
740368c31abSDavid du Colombier int index[VtPointerDepth+1];
741368c31abSDavid du Colombier VtEntry e;
742368c31abSDavid du Colombier int i;
743368c31abSDavid du Colombier
744368c31abSDavid du Colombier assert(ISLOCKED(r));
745368c31abSDavid du Colombier assert(bn != NilBlock);
746368c31abSDavid du Colombier
747368c31abSDavid du Colombier b = fileload(r, &e);
748368c31abSDavid du Colombier if(b == nil)
749368c31abSDavid du Colombier return -1;
750368c31abSDavid du Colombier
751*9ba92a1aSDavid du Colombier if(DEPTH(e.type) == 0){
752*9ba92a1aSDavid du Colombier memmove(score, e.score, VtScoreSize);
753*9ba92a1aSDavid du Colombier vtblockput(b);
754*9ba92a1aSDavid du Colombier return 0;
755*9ba92a1aSDavid du Colombier }
756*9ba92a1aSDavid du Colombier
757368c31abSDavid du Colombier i = mkindices(&e, bn, index);
758368c31abSDavid du Colombier if(i < 0){
759368c31abSDavid du Colombier vtblockput(b);
760368c31abSDavid du Colombier return -1;
761368c31abSDavid du Colombier }
762368c31abSDavid du Colombier if(i > DEPTH(e.type)){
763368c31abSDavid du Colombier memmove(score, vtzeroscore, VtScoreSize);
764368c31abSDavid du Colombier vtblockput(b);
765368c31abSDavid du Colombier return 0;
766368c31abSDavid du Colombier }
767368c31abSDavid du Colombier
768368c31abSDavid du Colombier index[DEPTH(e.type)] = r->offset % r->epb;
769368c31abSDavid du Colombier
770368c31abSDavid du Colombier for(i=DEPTH(e.type); i>=1; i--){
771368c31abSDavid du Colombier bb = blockwalk(b, index[i], r->c, VtOREAD, &e);
772368c31abSDavid du Colombier if(bb == nil)
773368c31abSDavid du Colombier goto Err;
774368c31abSDavid du Colombier vtblockput(b);
775368c31abSDavid du Colombier b = bb;
776368c31abSDavid du Colombier if(memcmp(b->score, vtzeroscore, VtScoreSize) == 0)
777368c31abSDavid du Colombier break;
778368c31abSDavid du Colombier }
779368c31abSDavid du Colombier
780368c31abSDavid du Colombier memmove(score, b->data+index[0]*VtScoreSize, VtScoreSize);
781368c31abSDavid du Colombier vtblockput(b);
782368c31abSDavid du Colombier return 0;
783368c31abSDavid du Colombier
784368c31abSDavid du Colombier Err:
785368c31abSDavid du Colombier vtblockput(b);
786368c31abSDavid du Colombier return -1;
787368c31abSDavid du Colombier }
788368c31abSDavid du Colombier
789368c31abSDavid du Colombier void
vtfileincref(VtFile * r)790368c31abSDavid du Colombier vtfileincref(VtFile *r)
791368c31abSDavid du Colombier {
792368c31abSDavid du Colombier qlock(&r->lk);
793368c31abSDavid du Colombier r->ref++;
794368c31abSDavid du Colombier qunlock(&r->lk);
795368c31abSDavid du Colombier }
796368c31abSDavid du Colombier
797368c31abSDavid du Colombier void
vtfileclose(VtFile * r)798368c31abSDavid du Colombier vtfileclose(VtFile *r)
799368c31abSDavid du Colombier {
800368c31abSDavid du Colombier if(r == nil)
801368c31abSDavid du Colombier return;
802368c31abSDavid du Colombier qlock(&r->lk);
803368c31abSDavid du Colombier r->ref--;
804368c31abSDavid du Colombier if(r->ref){
805368c31abSDavid du Colombier qunlock(&r->lk);
806368c31abSDavid du Colombier return;
807368c31abSDavid du Colombier }
808368c31abSDavid du Colombier assert(r->ref == 0);
809368c31abSDavid du Colombier qunlock(&r->lk);
810368c31abSDavid du Colombier if(r->parent)
811368c31abSDavid du Colombier vtfileclose(r->parent);
812368c31abSDavid du Colombier memset(r, ~0, sizeof(*r));
813368c31abSDavid du Colombier vtfree(r);
814368c31abSDavid du Colombier }
815368c31abSDavid du Colombier
816368c31abSDavid du Colombier /*
817368c31abSDavid du Colombier * Retrieve the block containing the entry for r.
818368c31abSDavid du Colombier * If a snapshot has happened, we might need
819368c31abSDavid du Colombier * to get a new copy of the block. We avoid this
820368c31abSDavid du Colombier * in the common case by caching the score for
821368c31abSDavid du Colombier * the block and the last epoch in which it was valid.
822368c31abSDavid du Colombier *
823368c31abSDavid du Colombier * We use r->mode to tell the difference between active
824368c31abSDavid du Colombier * file system VtFiles (VtORDWR) and VtFiles for the
825368c31abSDavid du Colombier * snapshot file system (VtOREAD).
826368c31abSDavid du Colombier */
827368c31abSDavid du Colombier static VtBlock*
fileloadblock(VtFile * r,int mode)828368c31abSDavid du Colombier fileloadblock(VtFile *r, int mode)
829368c31abSDavid du Colombier {
830368c31abSDavid du Colombier char e[ERRMAX];
831368c31abSDavid du Colombier u32int addr;
832368c31abSDavid du Colombier VtBlock *b;
833368c31abSDavid du Colombier
834368c31abSDavid du Colombier switch(r->mode){
835368c31abSDavid du Colombier default:
836368c31abSDavid du Colombier assert(0);
837368c31abSDavid du Colombier case VtORDWR:
838368c31abSDavid du Colombier assert(r->mode == VtORDWR);
839368c31abSDavid du Colombier if(r->local == 1){
840368c31abSDavid du Colombier b = vtcacheglobal(r->c, r->score, VtDirType);
841368c31abSDavid du Colombier if(b == nil)
842368c31abSDavid du Colombier return nil;
843368c31abSDavid du Colombier b->pc = getcallerpc(&r);
844368c31abSDavid du Colombier return b;
845368c31abSDavid du Colombier }
846368c31abSDavid du Colombier assert(r->parent != nil);
847368c31abSDavid du Colombier if(vtfilelock(r->parent, VtORDWR) < 0)
848368c31abSDavid du Colombier return nil;
849368c31abSDavid du Colombier b = vtfileblock(r->parent, r->offset/r->epb, VtORDWR);
850368c31abSDavid du Colombier vtfileunlock(r->parent);
851368c31abSDavid du Colombier if(b == nil)
852368c31abSDavid du Colombier return nil;
853368c31abSDavid du Colombier memmove(r->score, b->score, VtScoreSize);
854368c31abSDavid du Colombier r->local = 1;
855368c31abSDavid du Colombier return b;
856368c31abSDavid du Colombier
857368c31abSDavid du Colombier case VtOREAD:
858368c31abSDavid du Colombier if(mode == VtORDWR){
859368c31abSDavid du Colombier werrstr("read/write lock of read-only file");
860368c31abSDavid du Colombier return nil;
861368c31abSDavid du Colombier }
862368c31abSDavid du Colombier addr = vtglobaltolocal(r->score);
863368c31abSDavid du Colombier if(addr == NilBlock)
864368c31abSDavid du Colombier return vtcacheglobal(r->c, r->score, VtDirType);
865368c31abSDavid du Colombier
866368c31abSDavid du Colombier b = vtcachelocal(r->c, addr, VtDirType);
867368c31abSDavid du Colombier if(b)
868368c31abSDavid du Colombier return b;
869368c31abSDavid du Colombier
870368c31abSDavid du Colombier /*
871368c31abSDavid du Colombier * If it failed because the epochs don't match, the block has been
872368c31abSDavid du Colombier * archived and reclaimed. Rewalk from the parent and get the
873368c31abSDavid du Colombier * new pointer. This can't happen in the VtORDWR case
874368c31abSDavid du Colombier * above because blocks in the current epoch don't get
875368c31abSDavid du Colombier * reclaimed. The fact that we're VtOREAD means we're
876368c31abSDavid du Colombier * a snapshot. (Or else the file system is read-only, but then
877368c31abSDavid du Colombier * the archiver isn't going around deleting blocks.)
878368c31abSDavid du Colombier */
879368c31abSDavid du Colombier rerrstr(e, sizeof e);
880368c31abSDavid du Colombier if(strcmp(e, ELabelMismatch) == 0){
881368c31abSDavid du Colombier if(vtfilelock(r->parent, VtOREAD) < 0)
882368c31abSDavid du Colombier return nil;
883368c31abSDavid du Colombier b = vtfileblock(r->parent, r->offset/r->epb, VtOREAD);
884368c31abSDavid du Colombier vtfileunlock(r->parent);
885368c31abSDavid du Colombier if(b){
886368c31abSDavid du Colombier fprint(2, "vtfilealloc: lost %V found %V\n",
887368c31abSDavid du Colombier r->score, b->score);
888368c31abSDavid du Colombier memmove(r->score, b->score, VtScoreSize);
889368c31abSDavid du Colombier return b;
890368c31abSDavid du Colombier }
891368c31abSDavid du Colombier }
892368c31abSDavid du Colombier return nil;
893368c31abSDavid du Colombier }
894368c31abSDavid du Colombier }
895368c31abSDavid du Colombier
896368c31abSDavid du Colombier int
vtfilelock(VtFile * r,int mode)897368c31abSDavid du Colombier vtfilelock(VtFile *r, int mode)
898368c31abSDavid du Colombier {
899368c31abSDavid du Colombier VtBlock *b;
900368c31abSDavid du Colombier
901368c31abSDavid du Colombier if(mode == -1)
902368c31abSDavid du Colombier mode = r->mode;
903368c31abSDavid du Colombier
904368c31abSDavid du Colombier b = fileloadblock(r, mode);
905368c31abSDavid du Colombier if(b == nil)
906368c31abSDavid du Colombier return -1;
907368c31abSDavid du Colombier /*
908368c31abSDavid du Colombier * The fact that we are holding b serves as the
909368c31abSDavid du Colombier * lock entitling us to write to r->b.
910368c31abSDavid du Colombier */
911368c31abSDavid du Colombier assert(r->b == nil);
912368c31abSDavid du Colombier r->b = b;
913368c31abSDavid du Colombier b->pc = getcallerpc(&r);
914368c31abSDavid du Colombier return 0;
915368c31abSDavid du Colombier }
916368c31abSDavid du Colombier
917368c31abSDavid du Colombier /*
918368c31abSDavid du Colombier * Lock two (usually sibling) VtFiles. This needs special care
919368c31abSDavid du Colombier * because the Entries for both vtFiles might be in the same block.
920368c31abSDavid du Colombier * We also try to lock blocks in left-to-right order within the tree.
921368c31abSDavid du Colombier */
922368c31abSDavid du Colombier int
vtfilelock2(VtFile * r,VtFile * rr,int mode)923368c31abSDavid du Colombier vtfilelock2(VtFile *r, VtFile *rr, int mode)
924368c31abSDavid du Colombier {
925368c31abSDavid du Colombier VtBlock *b, *bb;
926368c31abSDavid du Colombier
927368c31abSDavid du Colombier if(rr == nil)
928368c31abSDavid du Colombier return vtfilelock(r, mode);
929368c31abSDavid du Colombier
930368c31abSDavid du Colombier if(mode == -1)
931368c31abSDavid du Colombier mode = r->mode;
932368c31abSDavid du Colombier
933368c31abSDavid du Colombier if(r->parent==rr->parent && r->offset/r->epb == rr->offset/rr->epb){
934368c31abSDavid du Colombier b = fileloadblock(r, mode);
935368c31abSDavid du Colombier if(b == nil)
936368c31abSDavid du Colombier return -1;
937368c31abSDavid du Colombier vtblockduplock(b);
938368c31abSDavid du Colombier bb = b;
939368c31abSDavid du Colombier }else if(r->parent==rr->parent || r->offset > rr->offset){
940368c31abSDavid du Colombier bb = fileloadblock(rr, mode);
941368c31abSDavid du Colombier b = fileloadblock(r, mode);
942368c31abSDavid du Colombier }else{
943368c31abSDavid du Colombier b = fileloadblock(r, mode);
944368c31abSDavid du Colombier bb = fileloadblock(rr, mode);
945368c31abSDavid du Colombier }
946368c31abSDavid du Colombier if(b == nil || bb == nil){
947368c31abSDavid du Colombier if(b)
948368c31abSDavid du Colombier vtblockput(b);
949368c31abSDavid du Colombier if(bb)
950368c31abSDavid du Colombier vtblockput(bb);
951368c31abSDavid du Colombier return -1;
952368c31abSDavid du Colombier }
953368c31abSDavid du Colombier
954368c31abSDavid du Colombier /*
955368c31abSDavid du Colombier * The fact that we are holding b and bb serves
956368c31abSDavid du Colombier * as the lock entitling us to write to r->b and rr->b.
957368c31abSDavid du Colombier */
958368c31abSDavid du Colombier r->b = b;
959368c31abSDavid du Colombier rr->b = bb;
960368c31abSDavid du Colombier b->pc = getcallerpc(&r);
961368c31abSDavid du Colombier bb->pc = getcallerpc(&r);
962368c31abSDavid du Colombier return 0;
963368c31abSDavid du Colombier }
964368c31abSDavid du Colombier
965368c31abSDavid du Colombier void
vtfileunlock(VtFile * r)966368c31abSDavid du Colombier vtfileunlock(VtFile *r)
967368c31abSDavid du Colombier {
968368c31abSDavid du Colombier VtBlock *b;
969368c31abSDavid du Colombier
970368c31abSDavid du Colombier if(r->b == nil){
971368c31abSDavid du Colombier fprint(2, "vtfileunlock: already unlocked\n");
972368c31abSDavid du Colombier abort();
973368c31abSDavid du Colombier }
974368c31abSDavid du Colombier b = r->b;
975368c31abSDavid du Colombier r->b = nil;
976368c31abSDavid du Colombier vtblockput(b);
977368c31abSDavid du Colombier }
978368c31abSDavid du Colombier
979368c31abSDavid du Colombier static VtBlock*
fileload(VtFile * r,VtEntry * e)980368c31abSDavid du Colombier fileload(VtFile *r, VtEntry *e)
981368c31abSDavid du Colombier {
982368c31abSDavid du Colombier VtBlock *b;
983368c31abSDavid du Colombier
984368c31abSDavid du Colombier assert(ISLOCKED(r));
985368c31abSDavid du Colombier b = r->b;
986368c31abSDavid du Colombier if(vtentryunpack(e, b->data, r->offset % r->epb) < 0)
987368c31abSDavid du Colombier return nil;
988368c31abSDavid du Colombier vtblockduplock(b);
989368c31abSDavid du Colombier return b;
990368c31abSDavid du Colombier }
991368c31abSDavid du Colombier
992368c31abSDavid du Colombier static int
sizetodepth(uvlong s,int psize,int dsize)993368c31abSDavid du Colombier sizetodepth(uvlong s, int psize, int dsize)
994368c31abSDavid du Colombier {
995368c31abSDavid du Colombier int np;
996368c31abSDavid du Colombier int d;
997368c31abSDavid du Colombier
998368c31abSDavid du Colombier /* determine pointer depth */
999368c31abSDavid du Colombier np = psize/VtScoreSize;
1000368c31abSDavid du Colombier s = (s + dsize - 1)/dsize;
1001368c31abSDavid du Colombier for(d = 0; s > 1; d++)
1002368c31abSDavid du Colombier s = (s + np - 1)/np;
1003368c31abSDavid du Colombier return d;
1004368c31abSDavid du Colombier }
1005368c31abSDavid du Colombier
1006368c31abSDavid du Colombier long
vtfileread(VtFile * f,void * data,long count,vlong offset)1007368c31abSDavid du Colombier vtfileread(VtFile *f, void *data, long count, vlong offset)
1008368c31abSDavid du Colombier {
1009368c31abSDavid du Colombier int frag;
1010368c31abSDavid du Colombier VtBlock *b;
1011368c31abSDavid du Colombier VtEntry e;
1012368c31abSDavid du Colombier
1013368c31abSDavid du Colombier assert(ISLOCKED(f));
1014368c31abSDavid du Colombier
1015368c31abSDavid du Colombier vtfilegetentry(f, &e);
1016368c31abSDavid du Colombier if(count == 0)
1017368c31abSDavid du Colombier return 0;
1018368c31abSDavid du Colombier if(count < 0 || offset < 0){
1019368c31abSDavid du Colombier werrstr("vtfileread: bad offset or count");
1020368c31abSDavid du Colombier return -1;
1021368c31abSDavid du Colombier }
1022368c31abSDavid du Colombier if(offset >= e.size)
1023368c31abSDavid du Colombier return 0;
1024368c31abSDavid du Colombier
1025368c31abSDavid du Colombier if(offset+count > e.size)
1026368c31abSDavid du Colombier count = e.size - offset;
1027368c31abSDavid du Colombier
1028368c31abSDavid du Colombier frag = offset % e.dsize;
1029368c31abSDavid du Colombier if(frag+count > e.dsize)
1030368c31abSDavid du Colombier count = e.dsize - frag;
1031368c31abSDavid du Colombier
1032368c31abSDavid du Colombier b = vtfileblock(f, offset/e.dsize, VtOREAD);
1033368c31abSDavid du Colombier if(b == nil)
1034368c31abSDavid du Colombier return -1;
1035368c31abSDavid du Colombier
1036368c31abSDavid du Colombier memmove(data, b->data+frag, count);
1037368c31abSDavid du Colombier vtblockput(b);
1038368c31abSDavid du Colombier return count;
1039368c31abSDavid du Colombier }
1040368c31abSDavid du Colombier
1041368c31abSDavid du Colombier static long
filewrite1(VtFile * f,void * data,long count,vlong offset)1042368c31abSDavid du Colombier filewrite1(VtFile *f, void *data, long count, vlong offset)
1043368c31abSDavid du Colombier {
1044368c31abSDavid du Colombier int frag, m;
1045368c31abSDavid du Colombier VtBlock *b;
1046368c31abSDavid du Colombier VtEntry e;
1047368c31abSDavid du Colombier
1048368c31abSDavid du Colombier vtfilegetentry(f, &e);
1049368c31abSDavid du Colombier if(count < 0 || offset < 0){
1050368c31abSDavid du Colombier werrstr("vtfilewrite: bad offset or count");
1051368c31abSDavid du Colombier return -1;
1052368c31abSDavid du Colombier }
1053368c31abSDavid du Colombier
1054368c31abSDavid du Colombier frag = offset % e.dsize;
1055368c31abSDavid du Colombier if(frag+count > e.dsize)
1056368c31abSDavid du Colombier count = e.dsize - frag;
1057368c31abSDavid du Colombier
1058368c31abSDavid du Colombier m = VtORDWR;
1059368c31abSDavid du Colombier if(frag == 0 && count == e.dsize)
1060368c31abSDavid du Colombier m = VtOWRITE;
1061368c31abSDavid du Colombier
1062368c31abSDavid du Colombier b = vtfileblock(f, offset/e.dsize, m);
1063368c31abSDavid du Colombier if(b == nil)
1064368c31abSDavid du Colombier return -1;
1065368c31abSDavid du Colombier
1066368c31abSDavid du Colombier memmove(b->data+frag, data, count);
1067*9ba92a1aSDavid du Colombier if(m == VtOWRITE && frag+count < e.dsize)
1068*9ba92a1aSDavid du Colombier memset(b->data+frag+count, 0, e.dsize-frag-count);
1069368c31abSDavid du Colombier
1070368c31abSDavid du Colombier if(offset+count > e.size){
1071368c31abSDavid du Colombier vtfilegetentry(f, &e);
1072368c31abSDavid du Colombier e.size = offset+count;
1073368c31abSDavid du Colombier vtfilesetentry(f, &e);
1074368c31abSDavid du Colombier }
1075368c31abSDavid du Colombier
1076368c31abSDavid du Colombier vtblockput(b);
1077368c31abSDavid du Colombier return count;
1078368c31abSDavid du Colombier }
1079368c31abSDavid du Colombier
1080368c31abSDavid du Colombier long
vtfilewrite(VtFile * f,void * data,long count,vlong offset)1081368c31abSDavid du Colombier vtfilewrite(VtFile *f, void *data, long count, vlong offset)
1082368c31abSDavid du Colombier {
1083368c31abSDavid du Colombier long tot, m;
1084368c31abSDavid du Colombier
1085368c31abSDavid du Colombier assert(ISLOCKED(f));
1086368c31abSDavid du Colombier
1087368c31abSDavid du Colombier tot = 0;
1088368c31abSDavid du Colombier m = 0;
1089368c31abSDavid du Colombier while(tot < count){
1090368c31abSDavid du Colombier m = filewrite1(f, (char*)data+tot, count-tot, offset+tot);
1091368c31abSDavid du Colombier if(m <= 0)
1092368c31abSDavid du Colombier break;
1093368c31abSDavid du Colombier tot += m;
1094368c31abSDavid du Colombier }
1095368c31abSDavid du Colombier if(tot==0)
1096368c31abSDavid du Colombier return m;
1097368c31abSDavid du Colombier return tot;
1098368c31abSDavid du Colombier }
1099368c31abSDavid du Colombier
1100368c31abSDavid du Colombier static int
flushblock(VtCache * c,VtBlock * bb,uchar score[VtScoreSize],int ppb,int epb,int type)1101368c31abSDavid du Colombier flushblock(VtCache *c, VtBlock *bb, uchar score[VtScoreSize], int ppb, int epb,
1102368c31abSDavid du Colombier int type)
1103368c31abSDavid du Colombier {
1104368c31abSDavid du Colombier u32int addr;
1105368c31abSDavid du Colombier VtBlock *b;
1106368c31abSDavid du Colombier VtEntry e;
1107368c31abSDavid du Colombier int i;
1108368c31abSDavid du Colombier
1109368c31abSDavid du Colombier addr = vtglobaltolocal(score);
1110368c31abSDavid du Colombier if(addr == NilBlock)
1111368c31abSDavid du Colombier return 0;
1112368c31abSDavid du Colombier
1113368c31abSDavid du Colombier if(bb){
1114368c31abSDavid du Colombier b = bb;
1115368c31abSDavid du Colombier if(memcmp(b->score, score, VtScoreSize) != 0)
1116368c31abSDavid du Colombier abort();
1117368c31abSDavid du Colombier }else
1118368c31abSDavid du Colombier if((b = vtcachelocal(c, addr, type)) == nil)
1119368c31abSDavid du Colombier return -1;
1120368c31abSDavid du Colombier
1121368c31abSDavid du Colombier switch(type){
1122368c31abSDavid du Colombier case VtDataType:
1123368c31abSDavid du Colombier break;
1124368c31abSDavid du Colombier
1125368c31abSDavid du Colombier case VtDirType:
1126368c31abSDavid du Colombier for(i=0; i<epb; i++){
1127368c31abSDavid du Colombier if(vtentryunpack(&e, b->data, i) < 0)
1128368c31abSDavid du Colombier goto Err;
1129*9ba92a1aSDavid du Colombier if(!(e.flags&VtEntryActive))
1130*9ba92a1aSDavid du Colombier continue;
1131368c31abSDavid du Colombier if(flushblock(c, nil, e.score, e.psize/VtScoreSize, e.dsize/VtEntrySize,
1132368c31abSDavid du Colombier e.type) < 0)
1133368c31abSDavid du Colombier goto Err;
1134*9ba92a1aSDavid du Colombier vtentrypack(&e, b->data, i);
1135368c31abSDavid du Colombier }
1136368c31abSDavid du Colombier break;
1137368c31abSDavid du Colombier
1138368c31abSDavid du Colombier default: /* VtPointerTypeX */
1139368c31abSDavid du Colombier for(i=0; i<ppb; i++){
1140368c31abSDavid du Colombier if(flushblock(c, nil, b->data+VtScoreSize*i, ppb, epb, type-1) < 0)
1141368c31abSDavid du Colombier goto Err;
1142368c31abSDavid du Colombier }
1143368c31abSDavid du Colombier break;
1144368c31abSDavid du Colombier }
1145368c31abSDavid du Colombier
1146368c31abSDavid du Colombier if(vtblockwrite(b) < 0)
1147368c31abSDavid du Colombier goto Err;
1148368c31abSDavid du Colombier memmove(score, b->score, VtScoreSize);
1149368c31abSDavid du Colombier if(b != bb)
1150368c31abSDavid du Colombier vtblockput(b);
1151368c31abSDavid du Colombier return 0;
1152368c31abSDavid du Colombier
1153368c31abSDavid du Colombier Err:
1154368c31abSDavid du Colombier if(b != bb)
1155368c31abSDavid du Colombier vtblockput(b);
1156368c31abSDavid du Colombier return -1;
1157368c31abSDavid du Colombier }
1158368c31abSDavid du Colombier
1159368c31abSDavid du Colombier int
vtfileflush(VtFile * f)1160368c31abSDavid du Colombier vtfileflush(VtFile *f)
1161368c31abSDavid du Colombier {
1162368c31abSDavid du Colombier int ret;
1163368c31abSDavid du Colombier VtBlock *b;
1164368c31abSDavid du Colombier VtEntry e;
1165368c31abSDavid du Colombier
1166368c31abSDavid du Colombier assert(ISLOCKED(f));
1167368c31abSDavid du Colombier b = fileload(f, &e);
1168368c31abSDavid du Colombier if(!(e.flags&VtEntryLocal)){
1169368c31abSDavid du Colombier vtblockput(b);
1170368c31abSDavid du Colombier return 0;
1171368c31abSDavid du Colombier }
1172368c31abSDavid du Colombier
1173368c31abSDavid du Colombier ret = flushblock(f->c, nil, e.score, e.psize/VtScoreSize, e.dsize/VtEntrySize,
1174368c31abSDavid du Colombier e.type);
1175368c31abSDavid du Colombier if(ret < 0){
1176368c31abSDavid du Colombier vtblockput(b);
1177368c31abSDavid du Colombier return -1;
1178368c31abSDavid du Colombier }
1179368c31abSDavid du Colombier
1180368c31abSDavid du Colombier vtentrypack(&e, b->data, f->offset % f->epb);
1181368c31abSDavid du Colombier vtblockput(b);
1182368c31abSDavid du Colombier return 0;
1183368c31abSDavid du Colombier }
1184368c31abSDavid du Colombier
1185368c31abSDavid du Colombier int
vtfileflushbefore(VtFile * r,u64int offset)1186368c31abSDavid du Colombier vtfileflushbefore(VtFile *r, u64int offset)
1187368c31abSDavid du Colombier {
1188368c31abSDavid du Colombier VtBlock *b, *bb;
1189368c31abSDavid du Colombier VtEntry e;
1190368c31abSDavid du Colombier int i, base, depth, ppb, epb, doflush;
1191368c31abSDavid du Colombier int index[VtPointerDepth+1], j, ret;
1192368c31abSDavid du Colombier VtBlock *bi[VtPointerDepth+2];
1193368c31abSDavid du Colombier uchar *score;
1194368c31abSDavid du Colombier
1195368c31abSDavid du Colombier assert(ISLOCKED(r));
1196368c31abSDavid du Colombier if(offset == 0)
1197368c31abSDavid du Colombier return 0;
1198368c31abSDavid du Colombier
1199368c31abSDavid du Colombier b = fileload(r, &e);
1200368c31abSDavid du Colombier if(b == nil)
1201368c31abSDavid du Colombier return -1;
1202368c31abSDavid du Colombier
1203368c31abSDavid du Colombier /*
1204368c31abSDavid du Colombier * compute path through tree for the last written byte and the next one.
1205368c31abSDavid du Colombier */
1206368c31abSDavid du Colombier ret = -1;
1207368c31abSDavid du Colombier memset(bi, 0, sizeof bi);
1208368c31abSDavid du Colombier depth = DEPTH(e.type);
1209368c31abSDavid du Colombier bi[depth+1] = b;
1210368c31abSDavid du Colombier i = mkindices(&e, (offset-1)/e.dsize, index);
1211368c31abSDavid du Colombier if(i < 0)
1212368c31abSDavid du Colombier goto Err;
1213368c31abSDavid du Colombier if(i > depth)
1214368c31abSDavid du Colombier goto Err;
1215368c31abSDavid du Colombier ppb = e.psize / VtScoreSize;
1216368c31abSDavid du Colombier epb = e.dsize / VtEntrySize;
1217368c31abSDavid du Colombier
1218368c31abSDavid du Colombier /*
1219368c31abSDavid du Colombier * load the blocks along the last written byte
1220368c31abSDavid du Colombier */
1221368c31abSDavid du Colombier index[depth] = r->offset % r->epb;
1222368c31abSDavid du Colombier for(i=depth; i>=0; i--){
1223368c31abSDavid du Colombier bb = blockwalk(b, index[i], r->c, VtORDWR, &e);
1224368c31abSDavid du Colombier if(bb == nil)
1225368c31abSDavid du Colombier goto Err;
1226368c31abSDavid du Colombier bi[i] = bb;
1227368c31abSDavid du Colombier b = bb;
1228368c31abSDavid du Colombier }
1229368c31abSDavid du Colombier ret = 0;
1230368c31abSDavid du Colombier
1231368c31abSDavid du Colombier /*
1232368c31abSDavid du Colombier * walk up the path from leaf to root, flushing anything that
1233368c31abSDavid du Colombier * has been finished.
1234368c31abSDavid du Colombier */
1235368c31abSDavid du Colombier base = e.type&~VtTypeDepthMask;
1236368c31abSDavid du Colombier for(i=0; i<=depth; i++){
1237368c31abSDavid du Colombier doflush = 0;
1238368c31abSDavid du Colombier if(i == 0){
1239368c31abSDavid du Colombier /* leaf: data or dir block */
1240368c31abSDavid du Colombier if(offset%e.dsize == 0)
1241368c31abSDavid du Colombier doflush = 1;
1242368c31abSDavid du Colombier }else{
1243368c31abSDavid du Colombier /*
1244368c31abSDavid du Colombier * interior node: pointer blocks.
1245368c31abSDavid du Colombier * specifically, b = bi[i] is a block whose index[i-1]'th entry
1246368c31abSDavid du Colombier * points at bi[i-1].
1247368c31abSDavid du Colombier */
1248368c31abSDavid du Colombier b = bi[i];
1249368c31abSDavid du Colombier
1250368c31abSDavid du Colombier /*
1251368c31abSDavid du Colombier * the index entries up to but not including index[i-1] point at
1252368c31abSDavid du Colombier * finished blocks, so flush them for sure.
1253368c31abSDavid du Colombier */
1254368c31abSDavid du Colombier for(j=0; j<index[i-1]; j++)
1255368c31abSDavid du Colombier if(flushblock(r->c, nil, b->data+j*VtScoreSize, ppb, epb, base+i-1) < 0)
1256368c31abSDavid du Colombier goto Err;
1257368c31abSDavid du Colombier
1258368c31abSDavid du Colombier /*
1259368c31abSDavid du Colombier * if index[i-1] is the last entry in the block and is global
1260368c31abSDavid du Colombier * (i.e. the kid is flushed), then we can flush this block.
1261368c31abSDavid du Colombier */
1262368c31abSDavid du Colombier if(j==ppb-1 && vtglobaltolocal(b->data+j*VtScoreSize)==NilBlock)
1263368c31abSDavid du Colombier doflush = 1;
1264368c31abSDavid du Colombier }
1265368c31abSDavid du Colombier if(doflush){
1266368c31abSDavid du Colombier if(i == depth)
1267368c31abSDavid du Colombier score = e.score;
1268368c31abSDavid du Colombier else
1269368c31abSDavid du Colombier score = bi[i+1]->data+index[i]*VtScoreSize;
1270368c31abSDavid du Colombier if(flushblock(r->c, bi[i], score, ppb, epb, base+i) < 0)
1271368c31abSDavid du Colombier goto Err;
1272368c31abSDavid du Colombier }
1273368c31abSDavid du Colombier }
1274368c31abSDavid du Colombier
1275368c31abSDavid du Colombier Err:
1276368c31abSDavid du Colombier /* top: entry. do this always so that the score is up-to-date */
1277368c31abSDavid du Colombier vtentrypack(&e, bi[depth+1]->data, index[depth]);
1278368c31abSDavid du Colombier for(i=0; i<nelem(bi); i++)
1279368c31abSDavid du Colombier if(bi[i])
1280368c31abSDavid du Colombier vtblockput(bi[i]);
1281368c31abSDavid du Colombier return ret;
1282368c31abSDavid du Colombier }
1283