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