15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier #include "dat.h"
35e96a66cSDavid du Colombier #include "fns.h"
45e96a66cSDavid du Colombier #include "error.h"
5*3b86f2f8SDavid du Colombier #include "9.h"
65e96a66cSDavid du Colombier
75e96a66cSDavid du Colombier static int sizeToDepth(uvlong s, int psize, int dsize);
85e96a66cSDavid du Colombier static u32int tagGen(void);
95e96a66cSDavid du Colombier static Block *sourceLoad(Source *r, Entry *e);
105e96a66cSDavid du Colombier static int sourceShrinkDepth(Source*, Block*, Entry*, int);
115e96a66cSDavid du Colombier static int sourceShrinkSize(Source*, Entry*, uvlong);
125e96a66cSDavid du Colombier static int sourceGrowDepth(Source*, Block*, Entry*, int);
135e96a66cSDavid du Colombier
145e96a66cSDavid du Colombier #define sourceIsLocked(r) ((r)->b != nil)
155e96a66cSDavid du Colombier
165e96a66cSDavid du Colombier static Source *
sourceAlloc(Fs * fs,Block * b,Source * p,u32int offset,int mode,int issnapshot)1757195852SDavid du Colombier sourceAlloc(Fs *fs, Block *b, Source *p, u32int offset, int mode, int issnapshot)
185e96a66cSDavid du Colombier {
195e96a66cSDavid du Colombier int epb;
205e96a66cSDavid du Colombier u32int epoch;
21*3b86f2f8SDavid du Colombier char *pname = nil;
22*3b86f2f8SDavid du Colombier Source *r;
235e96a66cSDavid du Colombier Entry e;
245e96a66cSDavid du Colombier
255e96a66cSDavid du Colombier assert(p==nil || sourceIsLocked(p));
265e96a66cSDavid du Colombier
275e96a66cSDavid du Colombier if(p == nil){
285e96a66cSDavid du Colombier assert(offset == 0);
295e96a66cSDavid du Colombier epb = 1;
305e96a66cSDavid du Colombier }else
315e96a66cSDavid du Colombier epb = p->dsize / VtEntrySize;
325e96a66cSDavid du Colombier
335e96a66cSDavid du Colombier if(b->l.type != BtDir)
345e96a66cSDavid du Colombier goto Bad;
355e96a66cSDavid du Colombier
365e96a66cSDavid du Colombier /*
375e96a66cSDavid du Colombier * a non-active entry is the only thing that
385e96a66cSDavid du Colombier * can legitimately happen here. all the others
395e96a66cSDavid du Colombier * get prints.
405e96a66cSDavid du Colombier */
415e96a66cSDavid du Colombier if(!entryUnpack(&e, b->data, offset % epb)){
42*3b86f2f8SDavid du Colombier pname = sourceName(p);
43*3b86f2f8SDavid du Colombier consPrint("%s: %s %V: sourceAlloc: entryUnpack failed\n",
44*3b86f2f8SDavid du Colombier fs->name, pname, b->score);
455e96a66cSDavid du Colombier goto Bad;
465e96a66cSDavid du Colombier }
475e96a66cSDavid du Colombier if(!(e.flags & VtEntryActive)){
48*3b86f2f8SDavid du Colombier pname = sourceName(p);
49*3b86f2f8SDavid du Colombier if(0) consPrint("%s: %s %V: sourceAlloc: not active\n",
50*3b86f2f8SDavid du Colombier fs->name, pname, e.score);
515e96a66cSDavid du Colombier goto Bad;
525e96a66cSDavid du Colombier }
535e96a66cSDavid du Colombier if(e.psize < 256 || e.dsize < 256){
54*3b86f2f8SDavid du Colombier pname = sourceName(p);
55*3b86f2f8SDavid du Colombier consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud < 256\n",
56*3b86f2f8SDavid du Colombier fs->name, pname, e.score, e.psize, e.dsize);
575e96a66cSDavid du Colombier goto Bad;
585e96a66cSDavid du Colombier }
595e96a66cSDavid du Colombier
605e96a66cSDavid du Colombier if(e.depth < sizeToDepth(e.size, e.psize, e.dsize)){
61*3b86f2f8SDavid du Colombier pname = sourceName(p);
62*3b86f2f8SDavid du Colombier consPrint("%s: %s %V: sourceAlloc: depth %ud size %llud "
63*3b86f2f8SDavid du Colombier "psize %ud dsize %ud\n", fs->name, pname,
64*3b86f2f8SDavid du Colombier e.score, e.depth, e.size, e.psize, e.dsize);
655e96a66cSDavid du Colombier goto Bad;
665e96a66cSDavid du Colombier }
675e96a66cSDavid du Colombier
685e96a66cSDavid du Colombier if((e.flags & VtEntryLocal) && e.tag == 0){
69*3b86f2f8SDavid du Colombier pname = sourceName(p);
70*3b86f2f8SDavid du Colombier consPrint("%s: %s %V: sourceAlloc: flags %#ux tag %#ux\n",
71*3b86f2f8SDavid du Colombier fs->name, pname, e.score, e.flags, e.tag);
725e96a66cSDavid du Colombier goto Bad;
735e96a66cSDavid du Colombier }
745e96a66cSDavid du Colombier
755e96a66cSDavid du Colombier if(e.dsize > fs->blockSize || e.psize > fs->blockSize){
76*3b86f2f8SDavid du Colombier pname = sourceName(p);
77*3b86f2f8SDavid du Colombier consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud "
78*3b86f2f8SDavid du Colombier "> blocksize %ud\n", fs->name, pname, e.score,
79*3b86f2f8SDavid du Colombier e.psize, e.dsize, fs->blockSize);
805e96a66cSDavid du Colombier goto Bad;
815e96a66cSDavid du Colombier }
825e96a66cSDavid du Colombier
835e96a66cSDavid du Colombier epoch = b->l.epoch;
845e96a66cSDavid du Colombier if(mode == OReadWrite){
855e96a66cSDavid du Colombier if(e.snap != 0){
865e96a66cSDavid du Colombier vtSetError(ESnapRO);
875e96a66cSDavid du Colombier return nil;
885e96a66cSDavid du Colombier }
895e96a66cSDavid du Colombier }else if(e.snap != 0){
905e96a66cSDavid du Colombier if(e.snap < fs->elo){
915e96a66cSDavid du Colombier vtSetError(ESnapOld);
925e96a66cSDavid du Colombier return nil;
935e96a66cSDavid du Colombier }
945e96a66cSDavid du Colombier if(e.snap >= fs->ehi)
955e96a66cSDavid du Colombier goto Bad;
965e96a66cSDavid du Colombier epoch = e.snap;
975e96a66cSDavid du Colombier }
985e96a66cSDavid du Colombier
995e96a66cSDavid du Colombier r = vtMemAllocZ(sizeof(Source));
1005e96a66cSDavid du Colombier r->fs = fs;
1015e96a66cSDavid du Colombier r->mode = mode;
10257195852SDavid du Colombier r->issnapshot = issnapshot;
1035e96a66cSDavid du Colombier r->dsize = e.dsize;
1045e96a66cSDavid du Colombier r->gen = e.gen;
1055e96a66cSDavid du Colombier r->dir = (e.flags & VtEntryDir) != 0;
1065e96a66cSDavid du Colombier r->lk = vtLockAlloc();
1075e96a66cSDavid du Colombier r->ref = 1;
1085e96a66cSDavid du Colombier r->parent = p;
1095e96a66cSDavid du Colombier if(p){
1105e96a66cSDavid du Colombier vtLock(p->lk);
1115e96a66cSDavid du Colombier assert(mode == OReadOnly || p->mode == OReadWrite);
1125e96a66cSDavid du Colombier p->ref++;
1135e96a66cSDavid du Colombier vtUnlock(p->lk);
1145e96a66cSDavid du Colombier }
1155e96a66cSDavid du Colombier r->epoch = epoch;
116*3b86f2f8SDavid du Colombier // consPrint("sourceAlloc: have %V be.%d fse.%d %s\n", b->score,
117c168f9f3SDavid du Colombier // b->l.epoch, r->fs->ehi, mode == OReadWrite? "rw": "ro");
1185e96a66cSDavid du Colombier memmove(r->score, b->score, VtScoreSize);
1195e96a66cSDavid du Colombier r->scoreEpoch = b->l.epoch;
1205e96a66cSDavid du Colombier r->offset = offset;
1215e96a66cSDavid du Colombier r->epb = epb;
1225e96a66cSDavid du Colombier r->tag = b->l.tag;
1235e96a66cSDavid du Colombier
124*3b86f2f8SDavid du Colombier // consPrint("%s: sourceAlloc: %p -> %V %d\n", r, r->score, r->offset);
1255e96a66cSDavid du Colombier
1265e96a66cSDavid du Colombier return r;
1275e96a66cSDavid du Colombier Bad:
128*3b86f2f8SDavid du Colombier free(pname);
1295e96a66cSDavid du Colombier vtSetError(EBadEntry);
1305e96a66cSDavid du Colombier return nil;
1315e96a66cSDavid du Colombier }
1325e96a66cSDavid du Colombier
1335e96a66cSDavid du Colombier Source *
sourceRoot(Fs * fs,u32int addr,int mode)1345e96a66cSDavid du Colombier sourceRoot(Fs *fs, u32int addr, int mode)
1355e96a66cSDavid du Colombier {
1365e96a66cSDavid du Colombier Source *r;
1375e96a66cSDavid du Colombier Block *b;
1385e96a66cSDavid du Colombier
1395e96a66cSDavid du Colombier b = cacheLocalData(fs->cache, addr, BtDir, RootTag, mode, 0);
1405e96a66cSDavid du Colombier if(b == nil)
1415e96a66cSDavid du Colombier return nil;
1425e96a66cSDavid du Colombier
143e569ccb5SDavid du Colombier if(mode == OReadWrite && b->l.epoch != fs->ehi){
144*3b86f2f8SDavid du Colombier consPrint("sourceRoot: fs->ehi = %ud, b->l = %L\n",
145*3b86f2f8SDavid du Colombier fs->ehi, &b->l);
1465e96a66cSDavid du Colombier blockPut(b);
1475e96a66cSDavid du Colombier vtSetError(EBadRoot);
1485e96a66cSDavid du Colombier return nil;
1495e96a66cSDavid du Colombier }
1505e96a66cSDavid du Colombier
15157195852SDavid du Colombier r = sourceAlloc(fs, b, nil, 0, mode, 0);
1525e96a66cSDavid du Colombier blockPut(b);
1535e96a66cSDavid du Colombier return r;
1545e96a66cSDavid du Colombier }
1555e96a66cSDavid du Colombier
1565e96a66cSDavid du Colombier Source *
sourceOpen(Source * r,ulong offset,int mode,int issnapshot)15757195852SDavid du Colombier sourceOpen(Source *r, ulong offset, int mode, int issnapshot)
1585e96a66cSDavid du Colombier {
1595e96a66cSDavid du Colombier ulong bn;
1605e96a66cSDavid du Colombier Block *b;
1615e96a66cSDavid du Colombier
1625e96a66cSDavid du Colombier assert(sourceIsLocked(r));
1635e96a66cSDavid du Colombier if(r->mode == OReadWrite)
1645e96a66cSDavid du Colombier assert(r->epoch == r->b->l.epoch);
1655e96a66cSDavid du Colombier if(!r->dir){
1665e96a66cSDavid du Colombier vtSetError(ENotDir);
1675e96a66cSDavid du Colombier return nil;
1685e96a66cSDavid du Colombier }
1695e96a66cSDavid du Colombier
1705e96a66cSDavid du Colombier bn = offset/(r->dsize/VtEntrySize);
1715e96a66cSDavid du Colombier
1725e96a66cSDavid du Colombier b = sourceBlock(r, bn, mode);
1735e96a66cSDavid du Colombier if(b == nil)
1745e96a66cSDavid du Colombier return nil;
17557195852SDavid du Colombier r = sourceAlloc(r->fs, b, r, offset, mode, issnapshot);
1765e96a66cSDavid du Colombier blockPut(b);
1775e96a66cSDavid du Colombier return r;
1785e96a66cSDavid du Colombier }
1795e96a66cSDavid du Colombier
1805e96a66cSDavid du Colombier Source *
sourceCreate(Source * r,int dsize,int dir,u32int offset)1815e96a66cSDavid du Colombier sourceCreate(Source *r, int dsize, int dir, u32int offset)
1825e96a66cSDavid du Colombier {
183*3b86f2f8SDavid du Colombier int i, epb, psize;
1845e96a66cSDavid du Colombier u32int bn, size;
185*3b86f2f8SDavid du Colombier Block *b;
1865e96a66cSDavid du Colombier Entry e;
1875e96a66cSDavid du Colombier Source *rr;
1885e96a66cSDavid du Colombier
1895e96a66cSDavid du Colombier assert(sourceIsLocked(r));
1905e96a66cSDavid du Colombier
1915e96a66cSDavid du Colombier if(!r->dir){
1925e96a66cSDavid du Colombier vtSetError(ENotDir);
1935e96a66cSDavid du Colombier return nil;
1945e96a66cSDavid du Colombier }
1955e96a66cSDavid du Colombier
1965e96a66cSDavid du Colombier epb = r->dsize/VtEntrySize;
1975e96a66cSDavid du Colombier psize = (dsize/VtScoreSize)*VtScoreSize;
1985e96a66cSDavid du Colombier
1995e96a66cSDavid du Colombier size = sourceGetDirSize(r);
2005e96a66cSDavid du Colombier if(offset == 0){
2015e96a66cSDavid du Colombier /*
2025e96a66cSDavid du Colombier * look at a random block to see if we can find an empty entry
2035e96a66cSDavid du Colombier */
2045e96a66cSDavid du Colombier offset = lnrand(size+1);
2055e96a66cSDavid du Colombier offset -= offset % epb;
2065e96a66cSDavid du Colombier }
2075e96a66cSDavid du Colombier
2085e96a66cSDavid du Colombier /* try the given block and then try the last block */
2095e96a66cSDavid du Colombier for(;;){
2105e96a66cSDavid du Colombier bn = offset/epb;
2115e96a66cSDavid du Colombier b = sourceBlock(r, bn, OReadWrite);
2125e96a66cSDavid du Colombier if(b == nil)
2135e96a66cSDavid du Colombier return nil;
2145e96a66cSDavid du Colombier for(i=offset%r->epb; i<epb; i++){
2155e96a66cSDavid du Colombier entryUnpack(&e, b->data, i);
2165e96a66cSDavid du Colombier if((e.flags&VtEntryActive) == 0 && e.gen != ~0)
2175e96a66cSDavid du Colombier goto Found;
2185e96a66cSDavid du Colombier }
2195e96a66cSDavid du Colombier blockPut(b);
2205e96a66cSDavid du Colombier if(offset == size){
2215e96a66cSDavid du Colombier fprint(2, "sourceCreate: cannot happen\n");
2225e96a66cSDavid du Colombier vtSetError("sourceCreate: cannot happen");
2235e96a66cSDavid du Colombier return nil;
2245e96a66cSDavid du Colombier }
2255e96a66cSDavid du Colombier offset = size;
2265e96a66cSDavid du Colombier }
2275e96a66cSDavid du Colombier
2285e96a66cSDavid du Colombier Found:
2295e96a66cSDavid du Colombier /* found an entry - gen already set */
2305e96a66cSDavid du Colombier e.psize = psize;
2315e96a66cSDavid du Colombier e.dsize = dsize;
232fe853e23SDavid du Colombier assert(psize && dsize);
2335e96a66cSDavid du Colombier e.flags = VtEntryActive;
2345e96a66cSDavid du Colombier if(dir)
2355e96a66cSDavid du Colombier e.flags |= VtEntryDir;
2365e96a66cSDavid du Colombier e.depth = 0;
2375e96a66cSDavid du Colombier e.size = 0;
2385e96a66cSDavid du Colombier memmove(e.score, vtZeroScore, VtScoreSize);
2395e96a66cSDavid du Colombier e.tag = 0;
2405e96a66cSDavid du Colombier e.snap = 0;
2415e96a66cSDavid du Colombier e.archive = 0;
2425e96a66cSDavid du Colombier entryPack(&e, b->data, i);
2435e96a66cSDavid du Colombier blockDirty(b);
2445e96a66cSDavid du Colombier
2455e96a66cSDavid du Colombier offset = bn*epb + i;
2465e96a66cSDavid du Colombier if(offset+1 > size){
2475e96a66cSDavid du Colombier if(!sourceSetDirSize(r, offset+1)){
2485e96a66cSDavid du Colombier blockPut(b);
2495e96a66cSDavid du Colombier return nil;
2505e96a66cSDavid du Colombier }
2515e96a66cSDavid du Colombier }
2525e96a66cSDavid du Colombier
25357195852SDavid du Colombier rr = sourceAlloc(r->fs, b, r, offset, OReadWrite, 0);
2545e96a66cSDavid du Colombier blockPut(b);
2555e96a66cSDavid du Colombier return rr;
2565e96a66cSDavid du Colombier }
2575e96a66cSDavid du Colombier
2585e96a66cSDavid du Colombier static int
sourceKill(Source * r,int doremove)2595e96a66cSDavid du Colombier sourceKill(Source *r, int doremove)
2605e96a66cSDavid du Colombier {
2615e96a66cSDavid du Colombier Entry e;
2625e96a66cSDavid du Colombier Block *b;
2635e96a66cSDavid du Colombier u32int addr;
2645e96a66cSDavid du Colombier u32int tag;
2655e96a66cSDavid du Colombier int type;
2665e96a66cSDavid du Colombier
2675e96a66cSDavid du Colombier assert(sourceIsLocked(r));
2685e96a66cSDavid du Colombier b = sourceLoad(r, &e);
2695e96a66cSDavid du Colombier if(b == nil)
2705e96a66cSDavid du Colombier return 0;
2715e96a66cSDavid du Colombier
2725e96a66cSDavid du Colombier assert(b->l.epoch == r->fs->ehi);
2735e96a66cSDavid du Colombier
2745e96a66cSDavid du Colombier if(doremove==0 && e.size == 0){
2755e96a66cSDavid du Colombier /* already truncated */
2765e96a66cSDavid du Colombier blockPut(b);
2775e96a66cSDavid du Colombier return 1;
2785e96a66cSDavid du Colombier }
2795e96a66cSDavid du Colombier
2805e96a66cSDavid du Colombier /* remember info on link we are removing */
2815e96a66cSDavid du Colombier addr = globalToLocal(e.score);
2825e96a66cSDavid du Colombier type = entryType(&e);
2835e96a66cSDavid du Colombier tag = e.tag;
2845e96a66cSDavid du Colombier
2855e96a66cSDavid du Colombier if(doremove){
2865e96a66cSDavid du Colombier if(e.gen != ~0)
2875e96a66cSDavid du Colombier e.gen++;
2885e96a66cSDavid du Colombier e.dsize = 0;
2895e96a66cSDavid du Colombier e.psize = 0;
2905e96a66cSDavid du Colombier e.flags = 0;
2915e96a66cSDavid du Colombier }else{
2925e96a66cSDavid du Colombier e.flags &= ~VtEntryLocal;
2935e96a66cSDavid du Colombier }
2945e96a66cSDavid du Colombier e.depth = 0;
2955e96a66cSDavid du Colombier e.size = 0;
2965e96a66cSDavid du Colombier e.tag = 0;
2975e96a66cSDavid du Colombier memmove(e.score, vtZeroScore, VtScoreSize);
2985e96a66cSDavid du Colombier entryPack(&e, b->data, r->offset % r->epb);
2995e96a66cSDavid du Colombier blockDirty(b);
3005e96a66cSDavid du Colombier if(addr != NilBlock)
301e569ccb5SDavid du Colombier blockRemoveLink(b, addr, type, tag, 1);
3025e96a66cSDavid du Colombier blockPut(b);
3035e96a66cSDavid du Colombier
3045e96a66cSDavid du Colombier if(doremove){
3055e96a66cSDavid du Colombier sourceUnlock(r);
3065e96a66cSDavid du Colombier sourceClose(r);
3075e96a66cSDavid du Colombier }
3085e96a66cSDavid du Colombier
3095e96a66cSDavid du Colombier return 1;
3105e96a66cSDavid du Colombier }
3115e96a66cSDavid du Colombier
3125e96a66cSDavid du Colombier int
sourceRemove(Source * r)3135e96a66cSDavid du Colombier sourceRemove(Source *r)
3145e96a66cSDavid du Colombier {
3155e96a66cSDavid du Colombier return sourceKill(r, 1);
3165e96a66cSDavid du Colombier }
3175e96a66cSDavid du Colombier
3185e96a66cSDavid du Colombier int
sourceTruncate(Source * r)3195e96a66cSDavid du Colombier sourceTruncate(Source *r)
3205e96a66cSDavid du Colombier {
3215e96a66cSDavid du Colombier return sourceKill(r, 0);
3225e96a66cSDavid du Colombier }
3235e96a66cSDavid du Colombier
3245e96a66cSDavid du Colombier uvlong
sourceGetSize(Source * r)3255e96a66cSDavid du Colombier sourceGetSize(Source *r)
3265e96a66cSDavid du Colombier {
3275e96a66cSDavid du Colombier Entry e;
3285e96a66cSDavid du Colombier Block *b;
3295e96a66cSDavid du Colombier
3305e96a66cSDavid du Colombier assert(sourceIsLocked(r));
3315e96a66cSDavid du Colombier b = sourceLoad(r, &e);
3325e96a66cSDavid du Colombier if(b == nil)
3335e96a66cSDavid du Colombier return 0;
3345e96a66cSDavid du Colombier blockPut(b);
3355e96a66cSDavid du Colombier
3365e96a66cSDavid du Colombier return e.size;
3375e96a66cSDavid du Colombier }
3385e96a66cSDavid du Colombier
3395e96a66cSDavid du Colombier static int
sourceShrinkSize(Source * r,Entry * e,uvlong size)3405e96a66cSDavid du Colombier sourceShrinkSize(Source *r, Entry *e, uvlong size)
3415e96a66cSDavid du Colombier {
3425e96a66cSDavid du Colombier int i, type, ppb;
3435e96a66cSDavid du Colombier uvlong ptrsz;
3445e96a66cSDavid du Colombier u32int addr;
3455e96a66cSDavid du Colombier uchar score[VtScoreSize];
3465e96a66cSDavid du Colombier Block *b;
3475e96a66cSDavid du Colombier
3485e96a66cSDavid du Colombier type = entryType(e);
3495e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite);
3505e96a66cSDavid du Colombier if(b == nil)
3515e96a66cSDavid du Colombier return 0;
3525e96a66cSDavid du Colombier
3535e96a66cSDavid du Colombier ptrsz = e->dsize;
3545e96a66cSDavid du Colombier ppb = e->psize/VtScoreSize;
3555e96a66cSDavid du Colombier for(i=0; i+1<e->depth; i++)
3565e96a66cSDavid du Colombier ptrsz *= ppb;
3575e96a66cSDavid du Colombier
3585e96a66cSDavid du Colombier while(type&BtLevelMask){
359e569ccb5SDavid du Colombier if(b->addr == NilBlock || b->l.epoch != r->fs->ehi){
3605e96a66cSDavid du Colombier /* not worth copying the block just so we can zero some of it */
3615e96a66cSDavid du Colombier blockPut(b);
3625e96a66cSDavid du Colombier return 0;
3635e96a66cSDavid du Colombier }
3645e96a66cSDavid du Colombier
3655e96a66cSDavid du Colombier /*
3665e96a66cSDavid du Colombier * invariant: each pointer in the tree rooted at b accounts for ptrsz bytes
3675e96a66cSDavid du Colombier */
3685e96a66cSDavid du Colombier
3695e96a66cSDavid du Colombier /* zero the pointers to unnecessary blocks */
3705e96a66cSDavid du Colombier i = (size+ptrsz-1)/ptrsz;
3715e96a66cSDavid du Colombier for(; i<ppb; i++){
3725e96a66cSDavid du Colombier addr = globalToLocal(b->data+i*VtScoreSize);
3735e96a66cSDavid du Colombier memmove(b->data+i*VtScoreSize, vtZeroScore, VtScoreSize);
3745e96a66cSDavid du Colombier blockDirty(b);
3755e96a66cSDavid du Colombier if(addr != NilBlock)
376e569ccb5SDavid du Colombier blockRemoveLink(b, addr, type-1, e->tag, 1);
3775e96a66cSDavid du Colombier }
3785e96a66cSDavid du Colombier
3795e96a66cSDavid du Colombier /* recurse (go around again) on the partially necessary block */
3805e96a66cSDavid du Colombier i = size/ptrsz;
3815e96a66cSDavid du Colombier size = size%ptrsz;
3825e96a66cSDavid du Colombier if(size == 0){
3835e96a66cSDavid du Colombier blockPut(b);
3845e96a66cSDavid du Colombier return 1;
3855e96a66cSDavid du Colombier }
3865e96a66cSDavid du Colombier ptrsz /= ppb;
3875e96a66cSDavid du Colombier type--;
3885e96a66cSDavid du Colombier memmove(score, b->data+i*VtScoreSize, VtScoreSize);
3895e96a66cSDavid du Colombier blockPut(b);
3905e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, score, type, e->tag, OReadWrite);
3915e96a66cSDavid du Colombier if(b == nil)
3925e96a66cSDavid du Colombier return 0;
3935e96a66cSDavid du Colombier }
3945e96a66cSDavid du Colombier
395e569ccb5SDavid du Colombier if(b->addr == NilBlock || b->l.epoch != r->fs->ehi){
3965e96a66cSDavid du Colombier blockPut(b);
3975e96a66cSDavid du Colombier return 0;
3985e96a66cSDavid du Colombier }
3995e96a66cSDavid du Colombier
4005e96a66cSDavid du Colombier /*
4015e96a66cSDavid du Colombier * No one ever truncates BtDir blocks.
4025e96a66cSDavid du Colombier */
4035e96a66cSDavid du Colombier if(type == BtData && e->dsize > size){
4045e96a66cSDavid du Colombier memset(b->data+size, 0, e->dsize-size);
4055e96a66cSDavid du Colombier blockDirty(b);
4065e96a66cSDavid du Colombier }
4075e96a66cSDavid du Colombier blockPut(b);
4085e96a66cSDavid du Colombier return 1;
4095e96a66cSDavid du Colombier }
4105e96a66cSDavid du Colombier
4115e96a66cSDavid du Colombier int
sourceSetSize(Source * r,uvlong size)4125e96a66cSDavid du Colombier sourceSetSize(Source *r, uvlong size)
4135e96a66cSDavid du Colombier {
4145e96a66cSDavid du Colombier int depth;
4155e96a66cSDavid du Colombier Entry e;
4165e96a66cSDavid du Colombier Block *b;
4175e96a66cSDavid du Colombier
4185e96a66cSDavid du Colombier assert(sourceIsLocked(r));
4195e96a66cSDavid du Colombier if(size == 0)
4205e96a66cSDavid du Colombier return sourceTruncate(r);
4215e96a66cSDavid du Colombier
4225e96a66cSDavid du Colombier if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize){
4235e96a66cSDavid du Colombier vtSetError(ETooBig);
4245e96a66cSDavid du Colombier return 0;
4255e96a66cSDavid du Colombier }
4265e96a66cSDavid du Colombier
4275e96a66cSDavid du Colombier b = sourceLoad(r, &e);
4285e96a66cSDavid du Colombier if(b == nil)
4295e96a66cSDavid du Colombier return 0;
4305e96a66cSDavid du Colombier
4315e96a66cSDavid du Colombier /* quick out */
4325e96a66cSDavid du Colombier if(e.size == size){
4335e96a66cSDavid du Colombier blockPut(b);
4345e96a66cSDavid du Colombier return 1;
4355e96a66cSDavid du Colombier }
4365e96a66cSDavid du Colombier
4375e96a66cSDavid du Colombier depth = sizeToDepth(size, e.psize, e.dsize);
4385e96a66cSDavid du Colombier
4395e96a66cSDavid du Colombier if(depth < e.depth){
4405e96a66cSDavid du Colombier if(!sourceShrinkDepth(r, b, &e, depth)){
4415e96a66cSDavid du Colombier blockPut(b);
4425e96a66cSDavid du Colombier return 0;
4435e96a66cSDavid du Colombier }
4445e96a66cSDavid du Colombier }else if(depth > e.depth){
4455e96a66cSDavid du Colombier if(!sourceGrowDepth(r, b, &e, depth)){
4465e96a66cSDavid du Colombier blockPut(b);
4475e96a66cSDavid du Colombier return 0;
4485e96a66cSDavid du Colombier }
4495e96a66cSDavid du Colombier }
4505e96a66cSDavid du Colombier
4515e96a66cSDavid du Colombier if(size < e.size)
4525e96a66cSDavid du Colombier sourceShrinkSize(r, &e, size);
4535e96a66cSDavid du Colombier
4545e96a66cSDavid du Colombier e.size = size;
4555e96a66cSDavid du Colombier entryPack(&e, b->data, r->offset % r->epb);
4565e96a66cSDavid du Colombier blockDirty(b);
4575e96a66cSDavid du Colombier blockPut(b);
4585e96a66cSDavid du Colombier
4595e96a66cSDavid du Colombier return 1;
4605e96a66cSDavid du Colombier }
4615e96a66cSDavid du Colombier
4625e96a66cSDavid du Colombier int
sourceSetDirSize(Source * r,ulong ds)4635e96a66cSDavid du Colombier sourceSetDirSize(Source *r, ulong ds)
4645e96a66cSDavid du Colombier {
4655e96a66cSDavid du Colombier uvlong size;
4665e96a66cSDavid du Colombier int epb;
4675e96a66cSDavid du Colombier
4685e96a66cSDavid du Colombier assert(sourceIsLocked(r));
4695e96a66cSDavid du Colombier epb = r->dsize/VtEntrySize;
4705e96a66cSDavid du Colombier
4715e96a66cSDavid du Colombier size = (uvlong)r->dsize*(ds/epb);
4725e96a66cSDavid du Colombier size += VtEntrySize*(ds%epb);
4735e96a66cSDavid du Colombier return sourceSetSize(r, size);
4745e96a66cSDavid du Colombier }
4755e96a66cSDavid du Colombier
4765e96a66cSDavid du Colombier ulong
sourceGetDirSize(Source * r)4775e96a66cSDavid du Colombier sourceGetDirSize(Source *r)
4785e96a66cSDavid du Colombier {
4795e96a66cSDavid du Colombier ulong ds;
4805e96a66cSDavid du Colombier uvlong size;
4815e96a66cSDavid du Colombier int epb;
4825e96a66cSDavid du Colombier
4835e96a66cSDavid du Colombier assert(sourceIsLocked(r));
4845e96a66cSDavid du Colombier epb = r->dsize/VtEntrySize;
4855e96a66cSDavid du Colombier
4865e96a66cSDavid du Colombier size = sourceGetSize(r);
4875e96a66cSDavid du Colombier ds = epb*(size/r->dsize);
4885e96a66cSDavid du Colombier ds += (size%r->dsize)/VtEntrySize;
4895e96a66cSDavid du Colombier return ds;
4905e96a66cSDavid du Colombier }
4915e96a66cSDavid du Colombier
4925e96a66cSDavid du Colombier int
sourceGetEntry(Source * r,Entry * e)4935e96a66cSDavid du Colombier sourceGetEntry(Source *r, Entry *e)
4945e96a66cSDavid du Colombier {
4955e96a66cSDavid du Colombier Block *b;
4965e96a66cSDavid du Colombier
4975e96a66cSDavid du Colombier assert(sourceIsLocked(r));
4985e96a66cSDavid du Colombier b = sourceLoad(r, e);
4995e96a66cSDavid du Colombier if(b == nil)
5005e96a66cSDavid du Colombier return 0;
5015e96a66cSDavid du Colombier blockPut(b);
5025e96a66cSDavid du Colombier
5035e96a66cSDavid du Colombier return 1;
5045e96a66cSDavid du Colombier }
5055e96a66cSDavid du Colombier
506fe853e23SDavid du Colombier /*
507fe853e23SDavid du Colombier * Must be careful with this. Doesn't record
508fe853e23SDavid du Colombier * dependencies, so don't introduce any!
509fe853e23SDavid du Colombier */
510fe853e23SDavid du Colombier int
sourceSetEntry(Source * r,Entry * e)511fe853e23SDavid du Colombier sourceSetEntry(Source *r, Entry *e)
512fe853e23SDavid du Colombier {
513fe853e23SDavid du Colombier Block *b;
514fe853e23SDavid du Colombier Entry oe;
515fe853e23SDavid du Colombier
516fe853e23SDavid du Colombier assert(sourceIsLocked(r));
517fe853e23SDavid du Colombier b = sourceLoad(r, &oe);
518fe853e23SDavid du Colombier if(b == nil)
519fe853e23SDavid du Colombier return 0;
520fe853e23SDavid du Colombier entryPack(e, b->data, r->offset%r->epb);
521fe853e23SDavid du Colombier blockDirty(b);
522fe853e23SDavid du Colombier blockPut(b);
523fe853e23SDavid du Colombier
524fe853e23SDavid du Colombier return 1;
525fe853e23SDavid du Colombier }
526fe853e23SDavid du Colombier
5275e96a66cSDavid du Colombier static Block *
blockWalk(Block * p,int index,int mode,Fs * fs,Entry * e)5285e96a66cSDavid du Colombier blockWalk(Block *p, int index, int mode, Fs *fs, Entry *e)
5295e96a66cSDavid du Colombier {
5305e96a66cSDavid du Colombier Block *b;
5315e96a66cSDavid du Colombier Cache *c;
5325e96a66cSDavid du Colombier u32int addr;
5335e96a66cSDavid du Colombier int type;
534fe853e23SDavid du Colombier uchar oscore[VtScoreSize], score[VtScoreSize];
53561201b97SDavid du Colombier Entry oe;
5365e96a66cSDavid du Colombier
5375e96a66cSDavid du Colombier c = fs->cache;
5385e96a66cSDavid du Colombier
5395e96a66cSDavid du Colombier if((p->l.type & BtLevelMask) == 0){
5405e96a66cSDavid du Colombier assert(p->l.type == BtDir);
5415e96a66cSDavid du Colombier type = entryType(e);
5425e96a66cSDavid du Colombier b = cacheGlobal(c, e->score, type, e->tag, mode);
5435e96a66cSDavid du Colombier }else{
5445e96a66cSDavid du Colombier type = p->l.type - 1;
5455e96a66cSDavid du Colombier b = cacheGlobal(c, p->data + index*VtScoreSize, type, e->tag, mode);
5465e96a66cSDavid du Colombier }
5475e96a66cSDavid du Colombier
548fe853e23SDavid du Colombier if(b)
549fe853e23SDavid du Colombier b->pc = getcallerpc(&p);
550fe853e23SDavid du Colombier
5515e96a66cSDavid du Colombier if(b == nil || mode == OReadOnly)
5525e96a66cSDavid du Colombier return b;
5535e96a66cSDavid du Colombier
554e569ccb5SDavid du Colombier if(p->l.epoch != fs->ehi){
555e569ccb5SDavid du Colombier fprint(2, "blockWalk: parent not writable\n");
556e569ccb5SDavid du Colombier abort();
557e569ccb5SDavid du Colombier }
558e569ccb5SDavid du Colombier if(b->l.epoch == fs->ehi)
5595e96a66cSDavid du Colombier return b;
5605e96a66cSDavid du Colombier
56161201b97SDavid du Colombier oe = *e;
56261201b97SDavid du Colombier
5635e96a66cSDavid du Colombier /*
5645e96a66cSDavid du Colombier * Copy on write.
5655e96a66cSDavid du Colombier */
5665e96a66cSDavid du Colombier if(e->tag == 0){
5675e96a66cSDavid du Colombier assert(p->l.type == BtDir);
5685e96a66cSDavid du Colombier e->tag = tagGen();
5695e96a66cSDavid du Colombier e->flags |= VtEntryLocal;
5705e96a66cSDavid du Colombier }
5715e96a66cSDavid du Colombier
5725e96a66cSDavid du Colombier addr = b->addr;
5735e96a66cSDavid du Colombier b = blockCopy(b, e->tag, fs->ehi, fs->elo);
5745e96a66cSDavid du Colombier if(b == nil)
5755e96a66cSDavid du Colombier return nil;
5765e96a66cSDavid du Colombier
577fe853e23SDavid du Colombier b->pc = getcallerpc(&p);
5785e96a66cSDavid du Colombier assert(b->l.epoch == fs->ehi);
5795e96a66cSDavid du Colombier
58061201b97SDavid du Colombier blockDirty(b);
581fe853e23SDavid du Colombier memmove(score, b->score, VtScoreSize);
5825e96a66cSDavid du Colombier if(p->l.type == BtDir){
5835e96a66cSDavid du Colombier memmove(e->score, b->score, VtScoreSize);
5845e96a66cSDavid du Colombier entryPack(e, p->data, index);
58561201b97SDavid du Colombier blockDependency(p, b, index, nil, &oe);
5865e96a66cSDavid du Colombier }else{
58761201b97SDavid du Colombier memmove(oscore, p->data+index*VtScoreSize, VtScoreSize);
5885e96a66cSDavid du Colombier memmove(p->data+index*VtScoreSize, b->score, VtScoreSize);
58961201b97SDavid du Colombier blockDependency(p, b, index, oscore, nil);
5905e96a66cSDavid du Colombier }
5915e96a66cSDavid du Colombier blockDirty(p);
5925e96a66cSDavid du Colombier
5935e96a66cSDavid du Colombier if(addr != NilBlock)
594e569ccb5SDavid du Colombier blockRemoveLink(p, addr, type, e->tag, 0);
5955e96a66cSDavid du Colombier
5965e96a66cSDavid du Colombier return b;
5975e96a66cSDavid du Colombier }
5985e96a66cSDavid du Colombier
5995e96a66cSDavid du Colombier /*
6005e96a66cSDavid du Colombier * Change the depth of the source r.
6015e96a66cSDavid du Colombier * The entry e for r is contained in block p.
6025e96a66cSDavid du Colombier */
6035e96a66cSDavid du Colombier static int
sourceGrowDepth(Source * r,Block * p,Entry * e,int depth)6045e96a66cSDavid du Colombier sourceGrowDepth(Source *r, Block *p, Entry *e, int depth)
6055e96a66cSDavid du Colombier {
6065e96a66cSDavid du Colombier Block *b, *bb;
6075e96a66cSDavid du Colombier u32int tag;
6085e96a66cSDavid du Colombier int type;
60961201b97SDavid du Colombier Entry oe;
6105e96a66cSDavid du Colombier
6115e96a66cSDavid du Colombier assert(sourceIsLocked(r));
6125e96a66cSDavid du Colombier assert(depth <= VtPointerDepth);
6135e96a66cSDavid du Colombier
6145e96a66cSDavid du Colombier type = entryType(e);
6155e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite);
6165e96a66cSDavid du Colombier if(b == nil)
6175e96a66cSDavid du Colombier return 0;
6185e96a66cSDavid du Colombier
6195e96a66cSDavid du Colombier tag = e->tag;
6205e96a66cSDavid du Colombier if(tag == 0)
6215e96a66cSDavid du Colombier tag = tagGen();
6225e96a66cSDavid du Colombier
62361201b97SDavid du Colombier oe = *e;
62461201b97SDavid du Colombier
6255e96a66cSDavid du Colombier /*
6265e96a66cSDavid du Colombier * Keep adding layers until we get to the right depth
6275e96a66cSDavid du Colombier * or an error occurs.
6285e96a66cSDavid du Colombier */
6295e96a66cSDavid du Colombier while(e->depth < depth){
6305e96a66cSDavid du Colombier bb = cacheAllocBlock(r->fs->cache, type+1, tag, r->fs->ehi, r->fs->elo);
6315e96a66cSDavid du Colombier if(bb == nil)
6325e96a66cSDavid du Colombier break;
633dc5a79c1SDavid du Colombier //fprint(2, "alloc %lux grow %V\n", bb->addr, b->score);
6345e96a66cSDavid du Colombier memmove(bb->data, b->score, VtScoreSize);
6355e96a66cSDavid du Colombier memmove(e->score, bb->score, VtScoreSize);
6365e96a66cSDavid du Colombier e->depth++;
6375e96a66cSDavid du Colombier type++;
6385e96a66cSDavid du Colombier e->tag = tag;
6395e96a66cSDavid du Colombier e->flags |= VtEntryLocal;
64061201b97SDavid du Colombier blockDependency(bb, b, 0, vtZeroScore, nil);
6415e96a66cSDavid du Colombier blockPut(b);
6425e96a66cSDavid du Colombier b = bb;
643fe853e23SDavid du Colombier blockDirty(b);
6445e96a66cSDavid du Colombier }
6455e96a66cSDavid du Colombier
6465e96a66cSDavid du Colombier entryPack(e, p->data, r->offset % r->epb);
64761201b97SDavid du Colombier blockDependency(p, b, r->offset % r->epb, nil, &oe);
6485e96a66cSDavid du Colombier blockPut(b);
6495e96a66cSDavid du Colombier blockDirty(p);
6505e96a66cSDavid du Colombier
6515e96a66cSDavid du Colombier return e->depth == depth;
6525e96a66cSDavid du Colombier }
6535e96a66cSDavid du Colombier
6545e96a66cSDavid du Colombier static int
sourceShrinkDepth(Source * r,Block * p,Entry * e,int depth)6555e96a66cSDavid du Colombier sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth)
6565e96a66cSDavid du Colombier {
6575e96a66cSDavid du Colombier Block *b, *nb, *ob, *rb;
6585e96a66cSDavid du Colombier u32int tag;
6595e96a66cSDavid du Colombier int type, d;
66061201b97SDavid du Colombier Entry oe;
6615e96a66cSDavid du Colombier
6625e96a66cSDavid du Colombier assert(sourceIsLocked(r));
6635e96a66cSDavid du Colombier assert(depth <= VtPointerDepth);
6645e96a66cSDavid du Colombier
6655e96a66cSDavid du Colombier type = entryType(e);
6665e96a66cSDavid du Colombier rb = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite);
6675e96a66cSDavid du Colombier if(rb == nil)
6685e96a66cSDavid du Colombier return 0;
6695e96a66cSDavid du Colombier
6705e96a66cSDavid du Colombier tag = e->tag;
6715e96a66cSDavid du Colombier if(tag == 0)
6725e96a66cSDavid du Colombier tag = tagGen();
6735e96a66cSDavid du Colombier
6745e96a66cSDavid du Colombier /*
6755e96a66cSDavid du Colombier * Walk down to the new root block.
6765e96a66cSDavid du Colombier * We may stop early, but something is better than nothing.
6775e96a66cSDavid du Colombier */
67861201b97SDavid du Colombier oe = *e;
67961201b97SDavid du Colombier
6805e96a66cSDavid du Colombier ob = nil;
6815e96a66cSDavid du Colombier b = rb;
682b5e190f4SDavid du Colombier /* BUG: explain type++. i think it is a real bug */
6835e96a66cSDavid du Colombier for(d=e->depth; d > depth; d--, type++){
6845e96a66cSDavid du Colombier nb = cacheGlobal(r->fs->cache, b->data, type-1, tag, OReadWrite);
6855e96a66cSDavid du Colombier if(nb == nil)
6865e96a66cSDavid du Colombier break;
6875e96a66cSDavid du Colombier if(ob!=nil && ob!=rb)
6885e96a66cSDavid du Colombier blockPut(ob);
6895e96a66cSDavid du Colombier ob = b;
6905e96a66cSDavid du Colombier b = nb;
6915e96a66cSDavid du Colombier }
6925e96a66cSDavid du Colombier
6935e96a66cSDavid du Colombier if(b == rb){
6945e96a66cSDavid du Colombier blockPut(rb);
6955e96a66cSDavid du Colombier return 0;
6965e96a66cSDavid du Colombier }
6975e96a66cSDavid du Colombier
6985e96a66cSDavid du Colombier /*
6995e96a66cSDavid du Colombier * Right now, e points at the root block rb, b is the new root block,
7005e96a66cSDavid du Colombier * and ob points at b. To update:
7015e96a66cSDavid du Colombier *
7025e96a66cSDavid du Colombier * (i) change e to point at b
7035e96a66cSDavid du Colombier * (ii) zero the pointer ob -> b
7045e96a66cSDavid du Colombier * (iii) free the root block
7055e96a66cSDavid du Colombier *
7065e96a66cSDavid du Colombier * p (the block containing e) must be written before
7075e96a66cSDavid du Colombier * anything else.
7085e96a66cSDavid du Colombier */
7095e96a66cSDavid du Colombier
7105e96a66cSDavid du Colombier /* (i) */
7115e96a66cSDavid du Colombier e->depth = d;
7122906cf0cSDavid du Colombier /* might have been local and now global; reverse cannot happen */
7132906cf0cSDavid du Colombier if(globalToLocal(b->score) == NilBlock)
7142906cf0cSDavid du Colombier e->flags &= ~VtEntryLocal;
7155e96a66cSDavid du Colombier memmove(e->score, b->score, VtScoreSize);
7165e96a66cSDavid du Colombier entryPack(e, p->data, r->offset % r->epb);
71761201b97SDavid du Colombier blockDependency(p, b, r->offset % r->epb, nil, &oe);
7185e96a66cSDavid du Colombier blockDirty(p);
7195e96a66cSDavid du Colombier
7205e96a66cSDavid du Colombier /* (ii) */
7215e96a66cSDavid du Colombier memmove(ob->data, vtZeroScore, VtScoreSize);
72261201b97SDavid du Colombier blockDependency(ob, p, 0, b->score, nil);
7235e96a66cSDavid du Colombier blockDirty(ob);
7245e96a66cSDavid du Colombier
7255e96a66cSDavid du Colombier /* (iii) */
7265e96a66cSDavid du Colombier if(rb->addr != NilBlock)
727e569ccb5SDavid du Colombier blockRemoveLink(p, rb->addr, rb->l.type, rb->l.tag, 1);
7285e96a66cSDavid du Colombier
7295e96a66cSDavid du Colombier blockPut(rb);
7305e96a66cSDavid du Colombier if(ob!=nil && ob!=rb)
7315e96a66cSDavid du Colombier blockPut(ob);
7325e96a66cSDavid du Colombier blockPut(b);
7335e96a66cSDavid du Colombier
7345e96a66cSDavid du Colombier return d == depth;
7355e96a66cSDavid du Colombier }
7365e96a66cSDavid du Colombier
737fe853e23SDavid du Colombier /*
738fe853e23SDavid du Colombier * Normally we return the block at the given number.
739fe853e23SDavid du Colombier * If early is set, we stop earlier in the tree. Setting early
740fe853e23SDavid du Colombier * to 1 gives us the block that contains the pointer to bn.
741fe853e23SDavid du Colombier */
7425e96a66cSDavid du Colombier Block *
_sourceBlock(Source * r,ulong bn,int mode,int early,ulong tag)743fe853e23SDavid du Colombier _sourceBlock(Source *r, ulong bn, int mode, int early, ulong tag)
7445e96a66cSDavid du Colombier {
7455e96a66cSDavid du Colombier Block *b, *bb;
7465e96a66cSDavid du Colombier int index[VtPointerDepth+1];
7475e96a66cSDavid du Colombier Entry e;
7485e96a66cSDavid du Colombier int i, np;
7495e96a66cSDavid du Colombier int m;
7505e96a66cSDavid du Colombier
7515e96a66cSDavid du Colombier assert(sourceIsLocked(r));
7525e96a66cSDavid du Colombier assert(bn != NilBlock);
7535e96a66cSDavid du Colombier
7545e96a66cSDavid du Colombier /* mode for intermediate block */
7555e96a66cSDavid du Colombier m = mode;
7565e96a66cSDavid du Colombier if(m == OOverWrite)
7575e96a66cSDavid du Colombier m = OReadWrite;
7585e96a66cSDavid du Colombier
7595e96a66cSDavid du Colombier b = sourceLoad(r, &e);
7605e96a66cSDavid du Colombier if(b == nil)
7615e96a66cSDavid du Colombier return nil;
76257195852SDavid du Colombier if(r->issnapshot && (e.flags & VtEntryNoArchive)){
763fe853e23SDavid du Colombier blockPut(b);
764fe853e23SDavid du Colombier vtSetError(ENotArchived);
765fe853e23SDavid du Colombier return nil;
766fe853e23SDavid du Colombier }
767fe853e23SDavid du Colombier
768fe853e23SDavid du Colombier if(tag){
769fe853e23SDavid du Colombier if(e.tag == 0)
770fe853e23SDavid du Colombier e.tag = tag;
771fe853e23SDavid du Colombier else if(e.tag != tag){
772fe853e23SDavid du Colombier fprint(2, "tag mismatch\n");
773fe853e23SDavid du Colombier vtSetError("tag mismatch");
774fe853e23SDavid du Colombier goto Err;
775fe853e23SDavid du Colombier }
776fe853e23SDavid du Colombier }
7775e96a66cSDavid du Colombier
7785e96a66cSDavid du Colombier np = e.psize/VtScoreSize;
7795e96a66cSDavid du Colombier memset(index, 0, sizeof(index));
7805e96a66cSDavid du Colombier for(i=0; bn > 0; i++){
7815e96a66cSDavid du Colombier if(i >= VtPointerDepth){
7825e96a66cSDavid du Colombier vtSetError(EBadAddr);
7835e96a66cSDavid du Colombier goto Err;
7845e96a66cSDavid du Colombier }
7855e96a66cSDavid du Colombier index[i] = bn % np;
7865e96a66cSDavid du Colombier bn /= np;
7875e96a66cSDavid du Colombier }
7885e96a66cSDavid du Colombier
7895e96a66cSDavid du Colombier if(i > e.depth){
7905e96a66cSDavid du Colombier if(mode == OReadOnly){
7915e96a66cSDavid du Colombier vtSetError(EBadAddr);
7925e96a66cSDavid du Colombier goto Err;
7935e96a66cSDavid du Colombier }
7945e96a66cSDavid du Colombier if(!sourceGrowDepth(r, b, &e, i))
7955e96a66cSDavid du Colombier goto Err;
7965e96a66cSDavid du Colombier }
7975e96a66cSDavid du Colombier
7985e96a66cSDavid du Colombier index[e.depth] = r->offset % r->epb;
7995e96a66cSDavid du Colombier
800fe853e23SDavid du Colombier for(i=e.depth; i>=early; i--){
8015e96a66cSDavid du Colombier bb = blockWalk(b, index[i], m, r->fs, &e);
8025e96a66cSDavid du Colombier if(bb == nil)
8035e96a66cSDavid du Colombier goto Err;
8045e96a66cSDavid du Colombier blockPut(b);
8055e96a66cSDavid du Colombier b = bb;
8065e96a66cSDavid du Colombier }
807fe853e23SDavid du Colombier b->pc = getcallerpc(&r);
8085e96a66cSDavid du Colombier return b;
8095e96a66cSDavid du Colombier Err:
8105e96a66cSDavid du Colombier blockPut(b);
8115e96a66cSDavid du Colombier return nil;
8125e96a66cSDavid du Colombier }
8135e96a66cSDavid du Colombier
814fe853e23SDavid du Colombier Block*
sourceBlock(Source * r,ulong bn,int mode)815fe853e23SDavid du Colombier sourceBlock(Source *r, ulong bn, int mode)
816fe853e23SDavid du Colombier {
817fe853e23SDavid du Colombier Block *b;
818fe853e23SDavid du Colombier
819fe853e23SDavid du Colombier b = _sourceBlock(r, bn, mode, 0, 0);
820fe853e23SDavid du Colombier if(b)
821fe853e23SDavid du Colombier b->pc = getcallerpc(&r);
822fe853e23SDavid du Colombier return b;
823fe853e23SDavid du Colombier }
824fe853e23SDavid du Colombier
8255e96a66cSDavid du Colombier void
sourceClose(Source * r)8265e96a66cSDavid du Colombier sourceClose(Source *r)
8275e96a66cSDavid du Colombier {
8285e96a66cSDavid du Colombier if(r == nil)
8295e96a66cSDavid du Colombier return;
8305e96a66cSDavid du Colombier vtLock(r->lk);
8315e96a66cSDavid du Colombier r->ref--;
8325e96a66cSDavid du Colombier if(r->ref){
8335e96a66cSDavid du Colombier vtUnlock(r->lk);
8345e96a66cSDavid du Colombier return;
8355e96a66cSDavid du Colombier }
8365e96a66cSDavid du Colombier assert(r->ref == 0);
8375e96a66cSDavid du Colombier vtUnlock(r->lk);
8385e96a66cSDavid du Colombier if(r->parent)
8395e96a66cSDavid du Colombier sourceClose(r->parent);
8405e96a66cSDavid du Colombier vtLockFree(r->lk);
8415e96a66cSDavid du Colombier memset(r, ~0, sizeof(*r));
8425e96a66cSDavid du Colombier vtMemFree(r);
8435e96a66cSDavid du Colombier }
8445e96a66cSDavid du Colombier
8455e96a66cSDavid du Colombier /*
8465e96a66cSDavid du Colombier * Retrieve the block containing the entry for r.
8475e96a66cSDavid du Colombier * If a snapshot has happened, we might need
8485e96a66cSDavid du Colombier * to get a new copy of the block. We avoid this
8495e96a66cSDavid du Colombier * in the common case by caching the score for
8505e96a66cSDavid du Colombier * the block and the last epoch in which it was valid.
8515e96a66cSDavid du Colombier *
8525e96a66cSDavid du Colombier * We use r->mode to tell the difference between active
8535e96a66cSDavid du Colombier * file system sources (OReadWrite) and sources for the
8545e96a66cSDavid du Colombier * snapshot file system (OReadOnly).
8555e96a66cSDavid du Colombier */
8565e96a66cSDavid du Colombier static Block*
sourceLoadBlock(Source * r,int mode)8575e96a66cSDavid du Colombier sourceLoadBlock(Source *r, int mode)
8585e96a66cSDavid du Colombier {
8595e96a66cSDavid du Colombier u32int addr;
8605e96a66cSDavid du Colombier Block *b;
8615e96a66cSDavid du Colombier
8625e96a66cSDavid du Colombier switch(r->mode){
8635e96a66cSDavid du Colombier default:
8645e96a66cSDavid du Colombier assert(0);
8655e96a66cSDavid du Colombier case OReadWrite:
8665e96a66cSDavid du Colombier assert(r->mode == OReadWrite);
86734e04225SDavid du Colombier /*
86834e04225SDavid du Colombier * This needn't be true -- we might bump the low epoch
86934e04225SDavid du Colombier * to reclaim some old blocks, but since this score is
87034e04225SDavid du Colombier * OReadWrite, the blocks must all still be open, so none
87134e04225SDavid du Colombier * are reclaimed. Thus it's okay that the epoch is so low.
87234e04225SDavid du Colombier * Proceed.
8735e96a66cSDavid du Colombier assert(r->epoch >= r->fs->elo);
87434e04225SDavid du Colombier */
8755e96a66cSDavid du Colombier if(r->epoch == r->fs->ehi){
8765e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite);
8775e96a66cSDavid du Colombier if(b == nil)
8785e96a66cSDavid du Colombier return nil;
8797611b47fSDavid du Colombier assert(r->epoch == b->l.epoch);
8805e96a66cSDavid du Colombier return b;
8815e96a66cSDavid du Colombier }
8825e96a66cSDavid du Colombier assert(r->parent != nil);
8835e96a66cSDavid du Colombier if(!sourceLock(r->parent, OReadWrite))
8845e96a66cSDavid du Colombier return nil;
8855e96a66cSDavid du Colombier b = sourceBlock(r->parent, r->offset/r->epb, OReadWrite);
8865e96a66cSDavid du Colombier sourceUnlock(r->parent);
8875e96a66cSDavid du Colombier if(b == nil)
8885e96a66cSDavid du Colombier return nil;
8895e96a66cSDavid du Colombier assert(b->l.epoch == r->fs->ehi);
890e569ccb5SDavid du Colombier // fprint(2, "sourceLoadBlock %p %V => %V\n", r, r->score, b->score);
8915e96a66cSDavid du Colombier memmove(r->score, b->score, VtScoreSize);
8925e96a66cSDavid du Colombier r->scoreEpoch = b->l.epoch;
8935e96a66cSDavid du Colombier r->tag = b->l.tag;
8945e96a66cSDavid du Colombier r->epoch = r->fs->ehi;
8955e96a66cSDavid du Colombier return b;
8965e96a66cSDavid du Colombier
8975e96a66cSDavid du Colombier case OReadOnly:
8985e96a66cSDavid du Colombier addr = globalToLocal(r->score);
8995e96a66cSDavid du Colombier if(addr == NilBlock)
9005e96a66cSDavid du Colombier return cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, mode);
9015e96a66cSDavid du Colombier
9025e96a66cSDavid du Colombier b = cacheLocalData(r->fs->cache, addr, BtDir, r->tag, mode, r->scoreEpoch);
9035e96a66cSDavid du Colombier if(b)
9045e96a66cSDavid du Colombier return b;
9055e96a66cSDavid du Colombier
9065e96a66cSDavid du Colombier /*
9075e96a66cSDavid du Colombier * If it failed because the epochs don't match, the block has been
9085e96a66cSDavid du Colombier * archived and reclaimed. Rewalk from the parent and get the
9095e96a66cSDavid du Colombier * new pointer. This can't happen in the OReadWrite case
9105e96a66cSDavid du Colombier * above because blocks in the current epoch don't get
9115e96a66cSDavid du Colombier * reclaimed. The fact that we're OReadOnly means we're
9125e96a66cSDavid du Colombier * a snapshot. (Or else the file system is read-only, but then
9135e96a66cSDavid du Colombier * the archiver isn't going around deleting blocks.)
9145e96a66cSDavid du Colombier */
9155e96a66cSDavid du Colombier if(strcmp(vtGetError(), ELabelMismatch) == 0){
9165e96a66cSDavid du Colombier if(!sourceLock(r->parent, OReadOnly))
9175e96a66cSDavid du Colombier return nil;
9185e96a66cSDavid du Colombier b = sourceBlock(r->parent, r->offset/r->epb, OReadOnly);
9195e96a66cSDavid du Colombier sourceUnlock(r->parent);
9205e96a66cSDavid du Colombier if(b){
9215e96a66cSDavid du Colombier fprint(2, "sourceAlloc: lost %V found %V\n",
9225e96a66cSDavid du Colombier r->score, b->score);
9235e96a66cSDavid du Colombier memmove(r->score, b->score, VtScoreSize);
9245e96a66cSDavid du Colombier r->scoreEpoch = b->l.epoch;
9255e96a66cSDavid du Colombier return b;
9265e96a66cSDavid du Colombier }
9275e96a66cSDavid du Colombier }
9285e96a66cSDavid du Colombier return nil;
9295e96a66cSDavid du Colombier }
9305e96a66cSDavid du Colombier }
9315e96a66cSDavid du Colombier
9325e96a66cSDavid du Colombier int
sourceLock(Source * r,int mode)9335e96a66cSDavid du Colombier sourceLock(Source *r, int mode)
9345e96a66cSDavid du Colombier {
9355e96a66cSDavid du Colombier Block *b;
9365e96a66cSDavid du Colombier
9375e96a66cSDavid du Colombier if(mode == -1)
9385e96a66cSDavid du Colombier mode = r->mode;
9395e96a66cSDavid du Colombier
9405e96a66cSDavid du Colombier b = sourceLoadBlock(r, mode);
9415e96a66cSDavid du Colombier if(b == nil)
9425e96a66cSDavid du Colombier return 0;
9435e96a66cSDavid du Colombier /*
9445e96a66cSDavid du Colombier * The fact that we are holding b serves as the
9455e96a66cSDavid du Colombier * lock entitling us to write to r->b.
9465e96a66cSDavid du Colombier */
9475e96a66cSDavid du Colombier assert(r->b == nil);
9485e96a66cSDavid du Colombier r->b = b;
9495e96a66cSDavid du Colombier if(r->mode == OReadWrite)
9505e96a66cSDavid du Colombier assert(r->epoch == r->b->l.epoch);
9515e96a66cSDavid du Colombier return 1;
9525e96a66cSDavid du Colombier }
9535e96a66cSDavid du Colombier
9545e96a66cSDavid du Colombier /*
9555e96a66cSDavid du Colombier * Lock two (usually sibling) sources. This needs special care
9565e96a66cSDavid du Colombier * because the Entries for both sources might be in the same block.
9575e96a66cSDavid du Colombier * We also try to lock blocks in left-to-right order within the tree.
9585e96a66cSDavid du Colombier */
9595e96a66cSDavid du Colombier int
sourceLock2(Source * r,Source * rr,int mode)9605e96a66cSDavid du Colombier sourceLock2(Source *r, Source *rr, int mode)
9615e96a66cSDavid du Colombier {
9625e96a66cSDavid du Colombier Block *b, *bb;
9635e96a66cSDavid du Colombier
9645e96a66cSDavid du Colombier if(rr == nil)
9655e96a66cSDavid du Colombier return sourceLock(r, mode);
9665e96a66cSDavid du Colombier
9675e96a66cSDavid du Colombier if(mode == -1)
9685e96a66cSDavid du Colombier mode = r->mode;
9695e96a66cSDavid du Colombier
9705e96a66cSDavid du Colombier if(r->parent==rr->parent && r->offset/r->epb == rr->offset/rr->epb){
9715e96a66cSDavid du Colombier b = sourceLoadBlock(r, mode);
9725e96a66cSDavid du Colombier if(b == nil)
9735e96a66cSDavid du Colombier return 0;
974e569ccb5SDavid du Colombier if(memcmp(r->score, rr->score, VtScoreSize) != 0){
975e569ccb5SDavid du Colombier memmove(rr->score, b->score, VtScoreSize);
976e569ccb5SDavid du Colombier rr->scoreEpoch = b->l.epoch;
977e569ccb5SDavid du Colombier rr->tag = b->l.tag;
978e569ccb5SDavid du Colombier rr->epoch = rr->fs->ehi;
979e569ccb5SDavid du Colombier }
9805e96a66cSDavid du Colombier blockDupLock(b);
9815e96a66cSDavid du Colombier bb = b;
9825e96a66cSDavid du Colombier }else if(r->parent==rr->parent || r->offset > rr->offset){
9835e96a66cSDavid du Colombier bb = sourceLoadBlock(rr, mode);
9845e96a66cSDavid du Colombier b = sourceLoadBlock(r, mode);
9855e96a66cSDavid du Colombier }else{
9865e96a66cSDavid du Colombier b = sourceLoadBlock(r, mode);
9875e96a66cSDavid du Colombier bb = sourceLoadBlock(rr, mode);
9885e96a66cSDavid du Colombier }
9895e96a66cSDavid du Colombier if(b == nil || bb == nil){
9905e96a66cSDavid du Colombier if(b)
9915e96a66cSDavid du Colombier blockPut(b);
9925e96a66cSDavid du Colombier if(bb)
9935e96a66cSDavid du Colombier blockPut(bb);
9945e96a66cSDavid du Colombier return 0;
9955e96a66cSDavid du Colombier }
9965e96a66cSDavid du Colombier
9975e96a66cSDavid du Colombier /*
9985e96a66cSDavid du Colombier * The fact that we are holding b and bb serves
9995e96a66cSDavid du Colombier * as the lock entitling us to write to r->b and rr->b.
10005e96a66cSDavid du Colombier */
10015e96a66cSDavid du Colombier r->b = b;
10025e96a66cSDavid du Colombier rr->b = bb;
10035e96a66cSDavid du Colombier return 1;
10045e96a66cSDavid du Colombier }
10055e96a66cSDavid du Colombier
10065e96a66cSDavid du Colombier void
sourceUnlock(Source * r)10075e96a66cSDavid du Colombier sourceUnlock(Source *r)
10085e96a66cSDavid du Colombier {
10095e96a66cSDavid du Colombier Block *b;
10105e96a66cSDavid du Colombier
10115e96a66cSDavid du Colombier if(r->b == nil){
10125e96a66cSDavid du Colombier fprint(2, "sourceUnlock: already unlocked\n");
10135e96a66cSDavid du Colombier abort();
10145e96a66cSDavid du Colombier }
10155e96a66cSDavid du Colombier b = r->b;
10165e96a66cSDavid du Colombier r->b = nil;
10175e96a66cSDavid du Colombier blockPut(b);
10185e96a66cSDavid du Colombier }
10195e96a66cSDavid du Colombier
10205e96a66cSDavid du Colombier static Block*
sourceLoad(Source * r,Entry * e)10215e96a66cSDavid du Colombier sourceLoad(Source *r, Entry *e)
10225e96a66cSDavid du Colombier {
10235e96a66cSDavid du Colombier Block *b;
10245e96a66cSDavid du Colombier
10255e96a66cSDavid du Colombier assert(sourceIsLocked(r));
10265e96a66cSDavid du Colombier b = r->b;
10275e96a66cSDavid du Colombier if(!entryUnpack(e, b->data, r->offset % r->epb))
10285e96a66cSDavid du Colombier return nil;
10295e96a66cSDavid du Colombier if(e->gen != r->gen){
10305e96a66cSDavid du Colombier vtSetError(ERemoved);
10315e96a66cSDavid du Colombier return nil;
10325e96a66cSDavid du Colombier }
10335e96a66cSDavid du Colombier blockDupLock(b);
10345e96a66cSDavid du Colombier return b;
10355e96a66cSDavid du Colombier }
10365e96a66cSDavid du Colombier
10375e96a66cSDavid du Colombier static int
sizeToDepth(uvlong s,int psize,int dsize)10385e96a66cSDavid du Colombier sizeToDepth(uvlong s, int psize, int dsize)
10395e96a66cSDavid du Colombier {
10405e96a66cSDavid du Colombier int np;
10415e96a66cSDavid du Colombier int d;
10425e96a66cSDavid du Colombier
10435e96a66cSDavid du Colombier /* determine pointer depth */
10445e96a66cSDavid du Colombier np = psize/VtScoreSize;
10455e96a66cSDavid du Colombier s = (s + dsize - 1)/dsize;
10465e96a66cSDavid du Colombier for(d = 0; s > 1; d++)
10475e96a66cSDavid du Colombier s = (s + np - 1)/np;
10485e96a66cSDavid du Colombier return d;
10495e96a66cSDavid du Colombier }
10505e96a66cSDavid du Colombier
10515e96a66cSDavid du Colombier static u32int
tagGen(void)10525e96a66cSDavid du Colombier tagGen(void)
10535e96a66cSDavid du Colombier {
10545e96a66cSDavid du Colombier u32int tag;
10555e96a66cSDavid du Colombier
10565e96a66cSDavid du Colombier for(;;){
10575e96a66cSDavid du Colombier tag = lrand();
10585e96a66cSDavid du Colombier if(tag >= UserTag)
10595e96a66cSDavid du Colombier break;
10605e96a66cSDavid du Colombier }
10615e96a66cSDavid du Colombier return tag;
10625e96a66cSDavid du Colombier }
1063*3b86f2f8SDavid du Colombier
1064*3b86f2f8SDavid du Colombier char *
sourceName(Source * s)1065*3b86f2f8SDavid du Colombier sourceName(Source *s)
1066*3b86f2f8SDavid du Colombier {
1067*3b86f2f8SDavid du Colombier return fileName(s->file);
1068*3b86f2f8SDavid du Colombier }
1069