Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 #include "error.h"
5 #include "9.h"
7 static int sizeToDepth(uvlong s, int psize, int dsize);
8 static u32int tagGen(void);
9 static Block *sourceLoad(Source *r, Entry *e);
10 static int sourceShrinkDepth(Source*, Block*, Entry*, int);
11 static int sourceShrinkSize(Source*, Entry*, uvlong);
12 static int sourceGrowDepth(Source*, Block*, Entry*, int);
14 #define sourceIsLocked(r) ((r)->b != nil)
16 static Source *
17 sourceAlloc(Fs *fs, Block *b, Source *p, u32int offset, int mode, int issnapshot)
18 {
19 int epb;
20 u32int epoch;
21 char *pname = nil;
22 Source *r;
23 Entry e;
25 assert(p==nil || sourceIsLocked(p));
27 if(p == nil){
28 assert(offset == 0);
29 epb = 1;
30 }else
31 epb = p->dsize / VtEntrySize;
33 if(b->l.type != BtDir)
34 goto Bad;
36 /*
37 * a non-active entry is the only thing that
38 * can legitimately happen here. all the others
39 * get prints.
40 */
41 if(!entryUnpack(&e, b->data, offset % epb)){
42 pname = sourceName(p);
43 consPrint("%s: %s %V: sourceAlloc: entryUnpack failed\n",
44 fs->name, pname, b->score);
45 goto Bad;
46 }
47 if(!(e.flags & VtEntryActive)){
48 pname = sourceName(p);
49 if(0) consPrint("%s: %s %V: sourceAlloc: not active\n",
50 fs->name, pname, e.score);
51 goto Bad;
52 }
53 if(e.psize < 256 || e.dsize < 256){
54 pname = sourceName(p);
55 consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud < 256\n",
56 fs->name, pname, e.score, e.psize, e.dsize);
57 goto Bad;
58 }
60 if(e.depth < sizeToDepth(e.size, e.psize, e.dsize)){
61 pname = sourceName(p);
62 consPrint("%s: %s %V: sourceAlloc: depth %ud size %llud "
63 "psize %ud dsize %ud\n", fs->name, pname,
64 e.score, e.depth, e.size, e.psize, e.dsize);
65 goto Bad;
66 }
68 if((e.flags & VtEntryLocal) && e.tag == 0){
69 pname = sourceName(p);
70 consPrint("%s: %s %V: sourceAlloc: flags %#ux tag %#ux\n",
71 fs->name, pname, e.score, e.flags, e.tag);
72 goto Bad;
73 }
75 if(e.dsize > fs->blockSize || e.psize > fs->blockSize){
76 pname = sourceName(p);
77 consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud "
78 "> blocksize %ud\n", fs->name, pname, e.score,
79 e.psize, e.dsize, fs->blockSize);
80 goto Bad;
81 }
83 epoch = b->l.epoch;
84 if(mode == OReadWrite){
85 if(e.snap != 0){
86 werrstr(ESnapRO);
87 return nil;
88 }
89 }else if(e.snap != 0){
90 if(e.snap < fs->elo){
91 werrstr(ESnapOld);
92 return nil;
93 }
94 if(e.snap >= fs->ehi)
95 goto Bad;
96 epoch = e.snap;
97 }
99 r = vtmallocz(sizeof(Source));
100 r->fs = fs;
101 r->mode = mode;
102 r->issnapshot = issnapshot;
103 r->dsize = e.dsize;
104 r->gen = e.gen;
105 r->dir = (e.flags & _VtEntryDir) != 0;
106 r->ref = 1;
107 r->parent = p;
108 if(p){
109 qlock(&p->lk);
110 assert(mode == OReadOnly || p->mode == OReadWrite);
111 p->ref++;
112 qunlock(&p->lk);
114 r->epoch = epoch;
115 // consPrint("sourceAlloc: have %V be.%d fse.%d %s\n", b->score,
116 // b->l.epoch, r->fs->ehi, mode == OReadWrite? "rw": "ro");
117 memmove(r->score, b->score, VtScoreSize);
118 r->scoreEpoch = b->l.epoch;
119 r->offset = offset;
120 r->epb = epb;
121 r->tag = b->l.tag;
123 // consPrint("%s: sourceAlloc: %p -> %V %d\n", r, r->score, r->offset);
125 return r;
126 Bad:
127 free(pname);
128 werrstr(EBadEntry);
129 return nil;
132 Source *
133 sourceRoot(Fs *fs, u32int addr, int mode)
135 Source *r;
136 Block *b;
138 b = cacheLocalData(fs->cache, addr, BtDir, RootTag, mode, 0);
139 if(b == nil)
140 return nil;
142 if(mode == OReadWrite && b->l.epoch != fs->ehi){
143 consPrint("sourceRoot: fs->ehi = %ud, b->l = %L\n",
144 fs->ehi, &b->l);
145 blockPut(b);
146 werrstr(EBadRoot);
147 return nil;
150 r = sourceAlloc(fs, b, nil, 0, mode, 0);
151 blockPut(b);
152 return r;
155 Source *
156 sourceOpen(Source *r, ulong offset, int mode, int issnapshot)
158 ulong bn;
159 Block *b;
161 assert(sourceIsLocked(r));
162 if(r->mode == OReadWrite)
163 assert(r->epoch == r->b->l.epoch);
164 if(!r->dir){
165 werrstr(ENotDir);
166 return nil;
169 bn = offset/(r->dsize/VtEntrySize);
171 b = sourceBlock(r, bn, mode);
172 if(b == nil)
173 return nil;
174 r = sourceAlloc(r->fs, b, r, offset, mode, issnapshot);
175 blockPut(b);
176 return r;
179 Source *
180 sourceCreate(Source *r, int dsize, int dir, u32int offset)
182 int i, epb, psize;
183 u32int bn, size;
184 Block *b;
185 Entry e;
186 Source *rr;
188 assert(sourceIsLocked(r));
190 if(!r->dir){
191 werrstr(ENotDir);
192 return nil;
195 epb = r->dsize/VtEntrySize;
196 psize = (dsize/VtScoreSize)*VtScoreSize;
198 size = sourceGetDirSize(r);
199 if(offset == 0){
200 /*
201 * look at a random block to see if we can find an empty entry
202 */
203 offset = lnrand(size+1);
204 offset -= offset % epb;
207 /* try the given block and then try the last block */
208 for(;;){
209 bn = offset/epb;
210 b = sourceBlock(r, bn, OReadWrite);
211 if(b == nil)
212 return nil;
213 for(i=offset%r->epb; i<epb; i++){
214 entryUnpack(&e, b->data, i);
215 if((e.flags&VtEntryActive) == 0 && e.gen != ~0)
216 goto Found;
218 blockPut(b);
219 if(offset == size){
220 fprint(2, "sourceCreate: cannot happen\n");
221 werrstr("sourceCreate: cannot happen");
222 return nil;
224 offset = size;
227 Found:
228 /* found an entry - gen already set */
229 e.psize = psize;
230 e.dsize = dsize;
231 assert(psize && dsize);
232 e.flags = VtEntryActive;
233 if(dir)
234 e.flags |= _VtEntryDir;
235 e.depth = 0;
236 e.size = 0;
237 memmove(e.score, vtzeroscore, VtScoreSize);
238 e.tag = 0;
239 e.snap = 0;
240 e.archive = 0;
241 entryPack(&e, b->data, i);
242 blockDirty(b);
244 offset = bn*epb + i;
245 if(offset+1 > size){
246 if(!sourceSetDirSize(r, offset+1)){
247 blockPut(b);
248 return nil;
252 rr = sourceAlloc(r->fs, b, r, offset, OReadWrite, 0);
253 blockPut(b);
254 return rr;
257 static int
258 sourceKill(Source *r, int doremove)
260 Entry e;
261 Block *b;
262 u32int addr;
263 u32int tag;
264 int type;
266 assert(sourceIsLocked(r));
267 b = sourceLoad(r, &e);
268 if(b == nil)
269 return 0;
271 assert(b->l.epoch == r->fs->ehi);
273 if(doremove==0 && e.size == 0){
274 /* already truncated */
275 blockPut(b);
276 return 1;
279 /* remember info on link we are removing */
280 addr = globalToLocal(e.score);
281 type = entryType(&e);
282 tag = e.tag;
284 if(doremove){
285 if(e.gen != ~0)
286 e.gen++;
287 e.dsize = 0;
288 e.psize = 0;
289 e.flags = 0;
290 }else{
291 e.flags &= ~VtEntryLocal;
293 e.depth = 0;
294 e.size = 0;
295 e.tag = 0;
296 memmove(e.score, vtzeroscore, VtScoreSize);
297 entryPack(&e, b->data, r->offset % r->epb);
298 blockDirty(b);
299 if(addr != NilBlock)
300 blockRemoveLink(b, addr, type, tag, 1);
301 blockPut(b);
303 if(doremove){
304 sourceUnlock(r);
305 sourceClose(r);
308 return 1;
311 int
312 sourceRemove(Source *r)
314 return sourceKill(r, 1);
317 int
318 sourceTruncate(Source *r)
320 return sourceKill(r, 0);
323 uvlong
324 sourceGetSize(Source *r)
326 Entry e;
327 Block *b;
329 assert(sourceIsLocked(r));
330 b = sourceLoad(r, &e);
331 if(b == nil)
332 return 0;
333 blockPut(b);
335 return e.size;
338 static int
339 sourceShrinkSize(Source *r, Entry *e, uvlong size)
341 int i, type, ppb;
342 uvlong ptrsz;
343 u32int addr;
344 uchar score[VtScoreSize];
345 Block *b;
347 type = entryType(e);
348 b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite);
349 if(b == nil)
350 return 0;
352 ptrsz = e->dsize;
353 ppb = e->psize/VtScoreSize;
354 for(i=0; i+1<e->depth; i++)
355 ptrsz *= ppb;
357 while(type&BtLevelMask){
358 if(b->addr == NilBlock || b->l.epoch != r->fs->ehi){
359 /* not worth copying the block just so we can zero some of it */
360 blockPut(b);
361 return 0;
364 /*
365 * invariant: each pointer in the tree rooted at b accounts for ptrsz bytes
366 */
368 /* zero the pointers to unnecessary blocks */
369 i = (size+ptrsz-1)/ptrsz;
370 for(; i<ppb; i++){
371 addr = globalToLocal(b->data+i*VtScoreSize);
372 memmove(b->data+i*VtScoreSize, vtzeroscore, VtScoreSize);
373 blockDirty(b);
374 if(addr != NilBlock)
375 blockRemoveLink(b, addr, type-1, e->tag, 1);
378 /* recurse (go around again) on the partially necessary block */
379 i = size/ptrsz;
380 size = size%ptrsz;
381 if(size == 0){
382 blockPut(b);
383 return 1;
385 ptrsz /= ppb;
386 type--;
387 memmove(score, b->data+i*VtScoreSize, VtScoreSize);
388 blockPut(b);
389 b = cacheGlobal(r->fs->cache, score, type, e->tag, OReadWrite);
390 if(b == nil)
391 return 0;
394 if(b->addr == NilBlock || b->l.epoch != r->fs->ehi){
395 blockPut(b);
396 return 0;
399 /*
400 * No one ever truncates BtDir blocks.
401 */
402 if(type == BtData && e->dsize > size){
403 memset(b->data+size, 0, e->dsize-size);
404 blockDirty(b);
406 blockPut(b);
407 return 1;
410 int
411 sourceSetSize(Source *r, uvlong size)
413 int depth;
414 Entry e;
415 Block *b;
417 assert(sourceIsLocked(r));
418 if(size == 0)
419 return sourceTruncate(r);
421 if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize){
422 werrstr(ETooBig);
423 return 0;
426 b = sourceLoad(r, &e);
427 if(b == nil)
428 return 0;
430 /* quick out */
431 if(e.size == size){
432 blockPut(b);
433 return 1;
436 depth = sizeToDepth(size, e.psize, e.dsize);
438 if(depth < e.depth){
439 if(!sourceShrinkDepth(r, b, &e, depth)){
440 blockPut(b);
441 return 0;
443 }else if(depth > e.depth){
444 if(!sourceGrowDepth(r, b, &e, depth)){
445 blockPut(b);
446 return 0;
450 if(size < e.size)
451 sourceShrinkSize(r, &e, size);
453 e.size = size;
454 entryPack(&e, b->data, r->offset % r->epb);
455 blockDirty(b);
456 blockPut(b);
458 return 1;
461 int
462 sourceSetDirSize(Source *r, ulong ds)
464 uvlong size;
465 int epb;
467 assert(sourceIsLocked(r));
468 epb = r->dsize/VtEntrySize;
470 size = (uvlong)r->dsize*(ds/epb);
471 size += VtEntrySize*(ds%epb);
472 return sourceSetSize(r, size);
475 ulong
476 sourceGetDirSize(Source *r)
478 ulong ds;
479 uvlong size;
480 int epb;
482 assert(sourceIsLocked(r));
483 epb = r->dsize/VtEntrySize;
485 size = sourceGetSize(r);
486 ds = epb*(size/r->dsize);
487 ds += (size%r->dsize)/VtEntrySize;
488 return ds;
491 int
492 sourceGetEntry(Source *r, Entry *e)
494 Block *b;
496 assert(sourceIsLocked(r));
497 b = sourceLoad(r, e);
498 if(b == nil)
499 return 0;
500 blockPut(b);
502 return 1;
505 /*
506 * Must be careful with this. Doesn't record
507 * dependencies, so don't introduce any!
508 */
509 int
510 sourceSetEntry(Source *r, Entry *e)
512 Block *b;
513 Entry oe;
515 assert(sourceIsLocked(r));
516 b = sourceLoad(r, &oe);
517 if(b == nil)
518 return 0;
519 entryPack(e, b->data, r->offset%r->epb);
520 blockDirty(b);
521 blockPut(b);
523 return 1;
526 static Block *
527 blockWalk(Block *p, int index, int mode, Fs *fs, Entry *e)
529 Block *b;
530 Cache *c;
531 u32int addr;
532 int type;
533 uchar oscore[VtScoreSize], score[VtScoreSize];
534 Entry oe;
536 c = fs->cache;
538 if((p->l.type & BtLevelMask) == 0){
539 assert(p->l.type == BtDir);
540 type = entryType(e);
541 b = cacheGlobal(c, e->score, type, e->tag, mode);
542 }else{
543 type = p->l.type - 1;
544 b = cacheGlobal(c, p->data + index*VtScoreSize, type, e->tag, mode);
547 if(b)
548 b->pc = getcallerpc(&p);
550 if(b == nil || mode == OReadOnly)
551 return b;
553 if(p->l.epoch != fs->ehi){
554 fprint(2, "blockWalk: parent not writable\n");
555 abort();
557 if(b->l.epoch == fs->ehi)
558 return b;
560 oe = *e;
562 /*
563 * Copy on write.
564 */
565 if(e->tag == 0){
566 assert(p->l.type == BtDir);
567 e->tag = tagGen();
568 e->flags |= VtEntryLocal;
571 addr = b->addr;
572 b = blockCopy(b, e->tag, fs->ehi, fs->elo);
573 if(b == nil)
574 return nil;
576 b->pc = getcallerpc(&p);
577 assert(b->l.epoch == fs->ehi);
579 blockDirty(b);
580 memmove(score, b->score, VtScoreSize);
581 if(p->l.type == BtDir){
582 memmove(e->score, b->score, VtScoreSize);
583 entryPack(e, p->data, index);
584 blockDependency(p, b, index, nil, &oe);
585 }else{
586 memmove(oscore, p->data+index*VtScoreSize, VtScoreSize);
587 memmove(p->data+index*VtScoreSize, b->score, VtScoreSize);
588 blockDependency(p, b, index, oscore, nil);
590 blockDirty(p);
592 if(addr != NilBlock)
593 blockRemoveLink(p, addr, type, e->tag, 0);
595 return b;
598 /*
599 * Change the depth of the source r.
600 * The entry e for r is contained in block p.
601 */
602 static int
603 sourceGrowDepth(Source *r, Block *p, Entry *e, int depth)
605 Block *b, *bb;
606 u32int tag;
607 int type;
608 Entry oe;
610 assert(sourceIsLocked(r));
611 assert(depth <= VtPointerDepth);
613 type = entryType(e);
614 b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite);
615 if(b == nil)
616 return 0;
618 tag = e->tag;
619 if(tag == 0)
620 tag = tagGen();
622 oe = *e;
624 /*
625 * Keep adding layers until we get to the right depth
626 * or an error occurs.
627 */
628 while(e->depth < depth){
629 bb = cacheAllocBlock(r->fs->cache, type+1, tag, r->fs->ehi, r->fs->elo);
630 if(bb == nil)
631 break;
632 //fprint(2, "alloc %lux grow %V\n", bb->addr, b->score);
633 memmove(bb->data, b->score, VtScoreSize);
634 memmove(e->score, bb->score, VtScoreSize);
635 e->depth++;
636 type++;
637 e->tag = tag;
638 e->flags |= VtEntryLocal;
639 blockDependency(bb, b, 0, vtzeroscore, nil);
640 blockPut(b);
641 b = bb;
642 blockDirty(b);
645 entryPack(e, p->data, r->offset % r->epb);
646 blockDependency(p, b, r->offset % r->epb, nil, &oe);
647 blockPut(b);
648 blockDirty(p);
650 return e->depth == depth;
653 static int
654 sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth)
656 Block *b, *nb, *ob, *rb;
657 u32int tag;
658 int type, d;
659 Entry oe;
661 assert(sourceIsLocked(r));
662 assert(depth <= VtPointerDepth);
664 type = entryType(e);
665 rb = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite);
666 if(rb == nil)
667 return 0;
669 tag = e->tag;
670 if(tag == 0)
671 tag = tagGen();
673 /*
674 * Walk down to the new root block.
675 * We may stop early, but something is better than nothing.
676 */
677 oe = *e;
679 ob = nil;
680 b = rb;
681 /* BUG: explain type++. i think it is a real bug */
682 for(d=e->depth; d > depth; d--, type++){
683 nb = cacheGlobal(r->fs->cache, b->data, type-1, tag, OReadWrite);
684 if(nb == nil)
685 break;
686 if(ob!=nil && ob!=rb)
687 blockPut(ob);
688 ob = b;
689 b = nb;
692 if(b == rb){
693 blockPut(rb);
694 return 0;
697 /*
698 * Right now, e points at the root block rb, b is the new root block,
699 * and ob points at b. To update:
701 * (i) change e to point at b
702 * (ii) zero the pointer ob -> b
703 * (iii) free the root block
705 * p (the block containing e) must be written before
706 * anything else.
707 */
709 /* (i) */
710 e->depth = d;
711 /* might have been local and now global; reverse cannot happen */
712 if(globalToLocal(b->score) == NilBlock)
713 e->flags &= ~VtEntryLocal;
714 memmove(e->score, b->score, VtScoreSize);
715 entryPack(e, p->data, r->offset % r->epb);
716 blockDependency(p, b, r->offset % r->epb, nil, &oe);
717 blockDirty(p);
719 /* (ii) */
720 memmove(ob->data, vtzeroscore, VtScoreSize);
721 blockDependency(ob, p, 0, b->score, nil);
722 blockDirty(ob);
724 /* (iii) */
725 if(rb->addr != NilBlock)
726 blockRemoveLink(p, rb->addr, rb->l.type, rb->l.tag, 1);
728 blockPut(rb);
729 if(ob!=nil && ob!=rb)
730 blockPut(ob);
731 blockPut(b);
733 return d == depth;
736 /*
737 * Normally we return the block at the given number.
738 * If early is set, we stop earlier in the tree. Setting early
739 * to 1 gives us the block that contains the pointer to bn.
740 */
741 Block *
742 _sourceBlock(Source *r, ulong bn, int mode, int early, ulong tag)
744 Block *b, *bb;
745 int index[VtPointerDepth+1];
746 Entry e;
747 int i, np;
748 int m;
750 assert(sourceIsLocked(r));
751 assert(bn != NilBlock);
753 /* mode for intermediate block */
754 m = mode;
755 if(m == OOverWrite)
756 m = OReadWrite;
758 b = sourceLoad(r, &e);
759 if(b == nil)
760 return nil;
761 if(r->issnapshot && (e.flags & VtEntryNoArchive)){
762 blockPut(b);
763 werrstr(ENotArchived);
764 return nil;
767 if(tag){
768 if(e.tag == 0)
769 e.tag = tag;
770 else if(e.tag != tag){
771 fprint(2, "tag mismatch\n");
772 werrstr("tag mismatch");
773 goto Err;
777 np = e.psize/VtScoreSize;
778 memset(index, 0, sizeof(index));
779 for(i=0; bn > 0; i++){
780 if(i >= VtPointerDepth){
781 werrstr(EBadAddr);
782 goto Err;
784 index[i] = bn % np;
785 bn /= np;
788 if(i > e.depth){
789 if(mode == OReadOnly){
790 werrstr(EBadAddr);
791 goto Err;
793 if(!sourceGrowDepth(r, b, &e, i))
794 goto Err;
797 index[e.depth] = r->offset % r->epb;
799 for(i=e.depth; i>=early; i--){
800 bb = blockWalk(b, index[i], m, r->fs, &e);
801 if(bb == nil)
802 goto Err;
803 blockPut(b);
804 b = bb;
806 b->pc = getcallerpc(&r);
807 return b;
808 Err:
809 blockPut(b);
810 return nil;
813 Block*
814 sourceBlock(Source *r, ulong bn, int mode)
816 Block *b;
818 b = _sourceBlock(r, bn, mode, 0, 0);
819 if(b)
820 b->pc = getcallerpc(&r);
821 return b;
824 void
825 sourceClose(Source *r)
827 if(r == nil)
828 return;
829 qlock(&r->lk);
830 r->ref--;
831 if(r->ref){
832 qunlock(&r->lk);
833 return;
835 assert(r->ref == 0);
836 qunlock(&r->lk);
837 if(r->parent)
838 sourceClose(r->parent);
839 memset(r, ~0, sizeof(*r));
840 vtfree(r);
843 /*
844 * Retrieve the block containing the entry for r.
845 * If a snapshot has happened, we might need
846 * to get a new copy of the block. We avoid this
847 * in the common case by caching the score for
848 * the block and the last epoch in which it was valid.
850 * We use r->mode to tell the difference between active
851 * file system sources (OReadWrite) and sources for the
852 * snapshot file system (OReadOnly).
853 */
854 static Block*
855 sourceLoadBlock(Source *r, int mode)
857 u32int addr;
858 Block *b;
859 char e[ERRMAX];
861 switch(r->mode){
862 default:
863 assert(0);
864 case OReadWrite:
865 assert(r->mode == OReadWrite);
866 /*
867 * This needn't be true -- we might bump the low epoch
868 * to reclaim some old blocks, but since this score is
869 * OReadWrite, the blocks must all still be open, so none
870 * are reclaimed. Thus it's okay that the epoch is so low.
871 * Proceed.
872 assert(r->epoch >= r->fs->elo);
873 */
874 if(r->epoch == r->fs->ehi){
875 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite);
876 if(b == nil)
877 return nil;
878 assert(r->epoch == b->l.epoch);
879 return b;
881 assert(r->parent != nil);
882 if(!sourceLock(r->parent, OReadWrite))
883 return nil;
884 b = sourceBlock(r->parent, r->offset/r->epb, OReadWrite);
885 sourceUnlock(r->parent);
886 if(b == nil)
887 return nil;
888 assert(b->l.epoch == r->fs->ehi);
889 // fprint(2, "sourceLoadBlock %p %V => %V\n", r, r->score, b->score);
890 memmove(r->score, b->score, VtScoreSize);
891 r->scoreEpoch = b->l.epoch;
892 r->tag = b->l.tag;
893 r->epoch = r->fs->ehi;
894 return b;
896 case OReadOnly:
897 addr = globalToLocal(r->score);
898 if(addr == NilBlock)
899 return cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, mode);
901 b = cacheLocalData(r->fs->cache, addr, BtDir, r->tag, mode, r->scoreEpoch);
902 if(b)
903 return b;
905 /*
906 * If it failed because the epochs don't match, the block has been
907 * archived and reclaimed. Rewalk from the parent and get the
908 * new pointer. This can't happen in the OReadWrite case
909 * above because blocks in the current epoch don't get
910 * reclaimed. The fact that we're OReadOnly means we're
911 * a snapshot. (Or else the file system is read-only, but then
912 * the archiver isn't going around deleting blocks.)
913 */
914 rerrstr(e, sizeof e);
915 if(strcmp(e, ELabelMismatch) == 0){
916 if(!sourceLock(r->parent, OReadOnly))
917 return nil;
918 b = sourceBlock(r->parent, r->offset/r->epb, OReadOnly);
919 sourceUnlock(r->parent);
920 if(b){
921 fprint(2, "sourceAlloc: lost %V found %V\n",
922 r->score, b->score);
923 memmove(r->score, b->score, VtScoreSize);
924 r->scoreEpoch = b->l.epoch;
925 return b;
928 return nil;
932 int
933 sourceLock(Source *r, int mode)
935 Block *b;
937 if(mode == -1)
938 mode = r->mode;
940 b = sourceLoadBlock(r, mode);
941 if(b == nil)
942 return 0;
943 /*
944 * The fact that we are holding b serves as the
945 * lock entitling us to write to r->b.
946 */
947 assert(r->b == nil);
948 r->b = b;
949 if(r->mode == OReadWrite)
950 assert(r->epoch == r->b->l.epoch);
951 return 1;
954 /*
955 * Lock two (usually sibling) sources. This needs special care
956 * because the Entries for both sources might be in the same block.
957 * We also try to lock blocks in left-to-right order within the tree.
958 */
959 int
960 sourceLock2(Source *r, Source *rr, int mode)
962 Block *b, *bb;
964 if(rr == nil)
965 return sourceLock(r, mode);
967 if(mode == -1)
968 mode = r->mode;
970 if(r->parent==rr->parent && r->offset/r->epb == rr->offset/rr->epb){
971 b = sourceLoadBlock(r, mode);
972 if(b == nil)
973 return 0;
974 if(memcmp(r->score, rr->score, VtScoreSize) != 0){
975 memmove(rr->score, b->score, VtScoreSize);
976 rr->scoreEpoch = b->l.epoch;
977 rr->tag = b->l.tag;
978 rr->epoch = rr->fs->ehi;
980 blockDupLock(b);
981 bb = b;
982 }else if(r->parent==rr->parent || r->offset > rr->offset){
983 bb = sourceLoadBlock(rr, mode);
984 b = sourceLoadBlock(r, mode);
985 }else{
986 b = sourceLoadBlock(r, mode);
987 bb = sourceLoadBlock(rr, mode);
989 if(b == nil || bb == nil){
990 if(b)
991 blockPut(b);
992 if(bb)
993 blockPut(bb);
994 return 0;
997 /*
998 * The fact that we are holding b and bb serves
999 * as the lock entitling us to write to r->b and rr->b.
1001 r->b = b;
1002 rr->b = bb;
1003 return 1;
1006 void
1007 sourceUnlock(Source *r)
1009 Block *b;
1011 if(r->b == nil){
1012 fprint(2, "sourceUnlock: already unlocked\n");
1013 abort();
1015 b = r->b;
1016 r->b = nil;
1017 blockPut(b);
1020 static Block*
1021 sourceLoad(Source *r, Entry *e)
1023 Block *b;
1025 assert(sourceIsLocked(r));
1026 b = r->b;
1027 if(!entryUnpack(e, b->data, r->offset % r->epb))
1028 return nil;
1029 if(e->gen != r->gen){
1030 werrstr(ERemoved);
1031 return nil;
1033 blockDupLock(b);
1034 return b;
1037 static int
1038 sizeToDepth(uvlong s, int psize, int dsize)
1040 int np;
1041 int d;
1043 /* determine pointer depth */
1044 np = psize/VtScoreSize;
1045 s = (s + dsize - 1)/dsize;
1046 for(d = 0; s > 1; d++)
1047 s = (s + np - 1)/np;
1048 return d;
1051 static u32int
1052 tagGen(void)
1054 u32int tag;
1056 for(;;){
1057 tag = lrand();
1058 if(tag >= UserTag)
1059 break;
1061 return tag;
1064 char *
1065 sourceName(Source *s)
1067 return fileName(s->file);