1*5e96a66cSDavid du Colombier #include "stdinc.h" 2*5e96a66cSDavid du Colombier #include "dat.h" 3*5e96a66cSDavid du Colombier #include "fns.h" 4*5e96a66cSDavid du Colombier #include "error.h" 5*5e96a66cSDavid du Colombier 6*5e96a66cSDavid du Colombier static int sizeToDepth(uvlong s, int psize, int dsize); 7*5e96a66cSDavid du Colombier static u32int tagGen(void); 8*5e96a66cSDavid du Colombier static Block *sourceLoad(Source *r, Entry *e); 9*5e96a66cSDavid du Colombier static Block *sourceLoadUnlocked(Source *r, Entry *e); 10*5e96a66cSDavid du Colombier static int sourceShrinkDepth(Source*, Block*, Entry*, int); 11*5e96a66cSDavid du Colombier static int sourceShrinkSize(Source*, Entry*, uvlong); 12*5e96a66cSDavid du Colombier static int sourceGrowDepth(Source*, Block*, Entry*, int); 13*5e96a66cSDavid du Colombier 14*5e96a66cSDavid du Colombier #define sourceIsLocked(r) ((r)->b != nil) 15*5e96a66cSDavid du Colombier 16*5e96a66cSDavid du Colombier static Source * 17*5e96a66cSDavid du Colombier sourceAlloc(Fs *fs, Block *b, Source *p, u32int offset, int mode) 18*5e96a66cSDavid du Colombier { 19*5e96a66cSDavid du Colombier Source *r; 20*5e96a66cSDavid du Colombier int epb; 21*5e96a66cSDavid du Colombier u32int epoch; 22*5e96a66cSDavid du Colombier Entry e; 23*5e96a66cSDavid du Colombier 24*5e96a66cSDavid du Colombier assert(p==nil || sourceIsLocked(p)); 25*5e96a66cSDavid du Colombier 26*5e96a66cSDavid du Colombier if(p == nil){ 27*5e96a66cSDavid du Colombier assert(offset == 0); 28*5e96a66cSDavid du Colombier epb = 1; 29*5e96a66cSDavid du Colombier }else 30*5e96a66cSDavid du Colombier epb = p->dsize / VtEntrySize; 31*5e96a66cSDavid du Colombier 32*5e96a66cSDavid du Colombier if(b->l.type != BtDir) 33*5e96a66cSDavid du Colombier goto Bad; 34*5e96a66cSDavid du Colombier 35*5e96a66cSDavid du Colombier /* 36*5e96a66cSDavid du Colombier * a non-active entry is the only thing that 37*5e96a66cSDavid du Colombier * can legitimately happen here. all the others 38*5e96a66cSDavid du Colombier * get prints. 39*5e96a66cSDavid du Colombier */ 40*5e96a66cSDavid du Colombier if(!entryUnpack(&e, b->data, offset % epb)){ 41*5e96a66cSDavid du Colombier fprint(2, "entryUnpack failed\n"); 42*5e96a66cSDavid du Colombier goto Bad; 43*5e96a66cSDavid du Colombier } 44*5e96a66cSDavid du Colombier if(!(e.flags & VtEntryActive)){ 45*5e96a66cSDavid du Colombier if(0)fprint(2, "not active\n"); 46*5e96a66cSDavid du Colombier goto Bad; 47*5e96a66cSDavid du Colombier } 48*5e96a66cSDavid du Colombier if(e.psize < 256 || e.dsize < 256){ 49*5e96a66cSDavid du Colombier fprint(2, "psize %ud dsize %ud\n", e.psize, e.dsize); 50*5e96a66cSDavid du Colombier goto Bad; 51*5e96a66cSDavid du Colombier } 52*5e96a66cSDavid du Colombier 53*5e96a66cSDavid du Colombier if(e.depth < sizeToDepth(e.size, e.psize, e.dsize)){ 54*5e96a66cSDavid du Colombier fprint(2, "depth %ud size %llud psize %ud dsize %ud\n", e.depth, e.size, e.psize, e.dsize); 55*5e96a66cSDavid du Colombier goto Bad; 56*5e96a66cSDavid du Colombier } 57*5e96a66cSDavid du Colombier 58*5e96a66cSDavid du Colombier if((e.flags & VtEntryLocal) && e.tag == 0){ 59*5e96a66cSDavid du Colombier fprint(2, "flags %#ux tag %#ux\n", e.flags, e.tag); 60*5e96a66cSDavid du Colombier goto Bad; 61*5e96a66cSDavid du Colombier } 62*5e96a66cSDavid du Colombier 63*5e96a66cSDavid du Colombier if(e.dsize > fs->blockSize || e.psize > fs->blockSize){ 64*5e96a66cSDavid du Colombier fprint(2, "psize %ud dsize %ud blocksize %ud\n", e.psize, e.dsize, fs->blockSize); 65*5e96a66cSDavid du Colombier goto Bad; 66*5e96a66cSDavid du Colombier } 67*5e96a66cSDavid du Colombier 68*5e96a66cSDavid du Colombier epoch = b->l.epoch; 69*5e96a66cSDavid du Colombier if(mode == OReadWrite){ 70*5e96a66cSDavid du Colombier if(e.snap != 0){ 71*5e96a66cSDavid du Colombier vtSetError(ESnapRO); 72*5e96a66cSDavid du Colombier return nil; 73*5e96a66cSDavid du Colombier } 74*5e96a66cSDavid du Colombier }else if(e.snap != 0){ 75*5e96a66cSDavid du Colombier if(e.snap < fs->elo){ 76*5e96a66cSDavid du Colombier vtSetError(ESnapOld); 77*5e96a66cSDavid du Colombier return nil; 78*5e96a66cSDavid du Colombier } 79*5e96a66cSDavid du Colombier if(e.snap >= fs->ehi) 80*5e96a66cSDavid du Colombier goto Bad; 81*5e96a66cSDavid du Colombier epoch = e.snap; 82*5e96a66cSDavid du Colombier } 83*5e96a66cSDavid du Colombier 84*5e96a66cSDavid du Colombier r = vtMemAllocZ(sizeof(Source)); 85*5e96a66cSDavid du Colombier r->fs = fs; 86*5e96a66cSDavid du Colombier r->mode = mode; 87*5e96a66cSDavid du Colombier r->dsize = e.dsize; 88*5e96a66cSDavid du Colombier r->gen = e.gen; 89*5e96a66cSDavid du Colombier r->dir = (e.flags & VtEntryDir) != 0; 90*5e96a66cSDavid du Colombier r->lk = vtLockAlloc(); 91*5e96a66cSDavid du Colombier r->ref = 1; 92*5e96a66cSDavid du Colombier r->parent = p; 93*5e96a66cSDavid du Colombier if(p){ 94*5e96a66cSDavid du Colombier vtLock(p->lk); 95*5e96a66cSDavid du Colombier assert(mode == OReadOnly || p->mode == OReadWrite); 96*5e96a66cSDavid du Colombier p->ref++; 97*5e96a66cSDavid du Colombier vtUnlock(p->lk); 98*5e96a66cSDavid du Colombier } 99*5e96a66cSDavid du Colombier r->epoch = epoch; 100*5e96a66cSDavid du Colombier //fprint(2, "sourceAlloc have %V be.%d fse.%d %s\n", b->score, b->l.epoch, r->fs->ehi, mode==OReadWrite ? "rw" : "ro"); 101*5e96a66cSDavid du Colombier memmove(r->score, b->score, VtScoreSize); 102*5e96a66cSDavid du Colombier r->scoreEpoch = b->l.epoch; 103*5e96a66cSDavid du Colombier r->offset = offset; 104*5e96a66cSDavid du Colombier r->epb = epb; 105*5e96a66cSDavid du Colombier r->tag = b->l.tag; 106*5e96a66cSDavid du Colombier 107*5e96a66cSDavid du Colombier //fprint(2, "sourceAlloc: %p -> %V %d\n", r, r->score, r->offset); 108*5e96a66cSDavid du Colombier 109*5e96a66cSDavid du Colombier return r; 110*5e96a66cSDavid du Colombier Bad: 111*5e96a66cSDavid du Colombier vtSetError(EBadEntry); 112*5e96a66cSDavid du Colombier return nil; 113*5e96a66cSDavid du Colombier 114*5e96a66cSDavid du Colombier } 115*5e96a66cSDavid du Colombier 116*5e96a66cSDavid du Colombier Source * 117*5e96a66cSDavid du Colombier sourceRoot(Fs *fs, u32int addr, int mode) 118*5e96a66cSDavid du Colombier { 119*5e96a66cSDavid du Colombier Source *r; 120*5e96a66cSDavid du Colombier Block *b; 121*5e96a66cSDavid du Colombier 122*5e96a66cSDavid du Colombier b = cacheLocalData(fs->cache, addr, BtDir, RootTag, mode, 0); 123*5e96a66cSDavid du Colombier if(b == nil) 124*5e96a66cSDavid du Colombier return nil; 125*5e96a66cSDavid du Colombier 126*5e96a66cSDavid du Colombier if(mode == OReadWrite) 127*5e96a66cSDavid du Colombier if((b->l.state&BsClosed) || b->l.epoch != fs->ehi){ 128*5e96a66cSDavid du Colombier fprint(2, "sourceRoot: fs->ehi = %ud, b->l = %L\n", fs->ehi, &b->l); 129*5e96a66cSDavid du Colombier blockPut(b); 130*5e96a66cSDavid du Colombier vtSetError(EBadRoot); 131*5e96a66cSDavid du Colombier return nil; 132*5e96a66cSDavid du Colombier } 133*5e96a66cSDavid du Colombier 134*5e96a66cSDavid du Colombier r = sourceAlloc(fs, b, nil, 0, mode); 135*5e96a66cSDavid du Colombier blockPut(b); 136*5e96a66cSDavid du Colombier return r; 137*5e96a66cSDavid du Colombier } 138*5e96a66cSDavid du Colombier 139*5e96a66cSDavid du Colombier Source * 140*5e96a66cSDavid du Colombier sourceOpen(Source *r, ulong offset, int mode) 141*5e96a66cSDavid du Colombier { 142*5e96a66cSDavid du Colombier ulong bn; 143*5e96a66cSDavid du Colombier Block *b; 144*5e96a66cSDavid du Colombier 145*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 146*5e96a66cSDavid du Colombier if(r->mode == OReadWrite) 147*5e96a66cSDavid du Colombier assert(r->epoch == r->b->l.epoch); 148*5e96a66cSDavid du Colombier if(!r->dir){ 149*5e96a66cSDavid du Colombier vtSetError(ENotDir); 150*5e96a66cSDavid du Colombier return nil; 151*5e96a66cSDavid du Colombier } 152*5e96a66cSDavid du Colombier 153*5e96a66cSDavid du Colombier bn = offset/(r->dsize/VtEntrySize); 154*5e96a66cSDavid du Colombier 155*5e96a66cSDavid du Colombier b = sourceBlock(r, bn, mode); 156*5e96a66cSDavid du Colombier if(b == nil) 157*5e96a66cSDavid du Colombier return nil; 158*5e96a66cSDavid du Colombier r = sourceAlloc(r->fs, b, r, offset, mode); 159*5e96a66cSDavid du Colombier blockPut(b); 160*5e96a66cSDavid du Colombier return r; 161*5e96a66cSDavid du Colombier } 162*5e96a66cSDavid du Colombier 163*5e96a66cSDavid du Colombier Source * 164*5e96a66cSDavid du Colombier sourceCreate(Source *r, int dsize, int dir, u32int offset) 165*5e96a66cSDavid du Colombier { 166*5e96a66cSDavid du Colombier int i; 167*5e96a66cSDavid du Colombier Block *b; 168*5e96a66cSDavid du Colombier u32int bn, size; 169*5e96a66cSDavid du Colombier Entry e; 170*5e96a66cSDavid du Colombier int epb; 171*5e96a66cSDavid du Colombier int psize; 172*5e96a66cSDavid du Colombier Source *rr; 173*5e96a66cSDavid du Colombier 174*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 175*5e96a66cSDavid du Colombier 176*5e96a66cSDavid du Colombier if(!r->dir){ 177*5e96a66cSDavid du Colombier vtSetError(ENotDir); 178*5e96a66cSDavid du Colombier return nil; 179*5e96a66cSDavid du Colombier } 180*5e96a66cSDavid du Colombier 181*5e96a66cSDavid du Colombier epb = r->dsize/VtEntrySize; 182*5e96a66cSDavid du Colombier psize = (dsize/VtScoreSize)*VtScoreSize; 183*5e96a66cSDavid du Colombier 184*5e96a66cSDavid du Colombier size = sourceGetDirSize(r); 185*5e96a66cSDavid du Colombier if(offset == 0){ 186*5e96a66cSDavid du Colombier /* 187*5e96a66cSDavid du Colombier * look at a random block to see if we can find an empty entry 188*5e96a66cSDavid du Colombier */ 189*5e96a66cSDavid du Colombier offset = lnrand(size+1); 190*5e96a66cSDavid du Colombier offset -= offset % epb; 191*5e96a66cSDavid du Colombier } 192*5e96a66cSDavid du Colombier 193*5e96a66cSDavid du Colombier /* try the given block and then try the last block */ 194*5e96a66cSDavid du Colombier for(;;){ 195*5e96a66cSDavid du Colombier bn = offset/epb; 196*5e96a66cSDavid du Colombier b = sourceBlock(r, bn, OReadWrite); 197*5e96a66cSDavid du Colombier if(b == nil) 198*5e96a66cSDavid du Colombier return nil; 199*5e96a66cSDavid du Colombier for(i=offset%r->epb; i<epb; i++){ 200*5e96a66cSDavid du Colombier entryUnpack(&e, b->data, i); 201*5e96a66cSDavid du Colombier if((e.flags&VtEntryActive) == 0 && e.gen != ~0) 202*5e96a66cSDavid du Colombier goto Found; 203*5e96a66cSDavid du Colombier } 204*5e96a66cSDavid du Colombier blockPut(b); 205*5e96a66cSDavid du Colombier if(offset == size){ 206*5e96a66cSDavid du Colombier fprint(2, "sourceCreate: cannot happen\n"); 207*5e96a66cSDavid du Colombier vtSetError("sourceCreate: cannot happen"); 208*5e96a66cSDavid du Colombier return nil; 209*5e96a66cSDavid du Colombier } 210*5e96a66cSDavid du Colombier offset = size; 211*5e96a66cSDavid du Colombier } 212*5e96a66cSDavid du Colombier 213*5e96a66cSDavid du Colombier Found: 214*5e96a66cSDavid du Colombier /* found an entry - gen already set */ 215*5e96a66cSDavid du Colombier e.psize = psize; 216*5e96a66cSDavid du Colombier e.dsize = dsize; 217*5e96a66cSDavid du Colombier e.flags = VtEntryActive; 218*5e96a66cSDavid du Colombier if(dir) 219*5e96a66cSDavid du Colombier e.flags |= VtEntryDir; 220*5e96a66cSDavid du Colombier e.depth = 0; 221*5e96a66cSDavid du Colombier e.size = 0; 222*5e96a66cSDavid du Colombier memmove(e.score, vtZeroScore, VtScoreSize); 223*5e96a66cSDavid du Colombier e.tag = 0; 224*5e96a66cSDavid du Colombier e.snap = 0; 225*5e96a66cSDavid du Colombier e.archive = 0; 226*5e96a66cSDavid du Colombier entryPack(&e, b->data, i); 227*5e96a66cSDavid du Colombier blockDirty(b); 228*5e96a66cSDavid du Colombier 229*5e96a66cSDavid du Colombier offset = bn*epb + i; 230*5e96a66cSDavid du Colombier if(offset+1 > size){ 231*5e96a66cSDavid du Colombier if(!sourceSetDirSize(r, offset+1)){ 232*5e96a66cSDavid du Colombier blockPut(b); 233*5e96a66cSDavid du Colombier return nil; 234*5e96a66cSDavid du Colombier } 235*5e96a66cSDavid du Colombier } 236*5e96a66cSDavid du Colombier 237*5e96a66cSDavid du Colombier rr = sourceAlloc(r->fs, b, r, offset, OReadWrite); 238*5e96a66cSDavid du Colombier blockPut(b); 239*5e96a66cSDavid du Colombier return rr; 240*5e96a66cSDavid du Colombier } 241*5e96a66cSDavid du Colombier 242*5e96a66cSDavid du Colombier static int 243*5e96a66cSDavid du Colombier sourceKill(Source *r, int doremove) 244*5e96a66cSDavid du Colombier { 245*5e96a66cSDavid du Colombier Entry e; 246*5e96a66cSDavid du Colombier Block *b; 247*5e96a66cSDavid du Colombier u32int addr; 248*5e96a66cSDavid du Colombier u32int tag; 249*5e96a66cSDavid du Colombier int type; 250*5e96a66cSDavid du Colombier 251*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 252*5e96a66cSDavid du Colombier b = sourceLoad(r, &e); 253*5e96a66cSDavid du Colombier if(b == nil) 254*5e96a66cSDavid du Colombier return 0; 255*5e96a66cSDavid du Colombier 256*5e96a66cSDavid du Colombier assert(b->l.epoch == r->fs->ehi); 257*5e96a66cSDavid du Colombier 258*5e96a66cSDavid du Colombier if(doremove==0 && e.size == 0){ 259*5e96a66cSDavid du Colombier /* already truncated */ 260*5e96a66cSDavid du Colombier blockPut(b); 261*5e96a66cSDavid du Colombier return 1; 262*5e96a66cSDavid du Colombier } 263*5e96a66cSDavid du Colombier 264*5e96a66cSDavid du Colombier /* remember info on link we are removing */ 265*5e96a66cSDavid du Colombier addr = globalToLocal(e.score); 266*5e96a66cSDavid du Colombier type = entryType(&e); 267*5e96a66cSDavid du Colombier tag = e.tag; 268*5e96a66cSDavid du Colombier 269*5e96a66cSDavid du Colombier if(doremove){ 270*5e96a66cSDavid du Colombier if(e.gen != ~0) 271*5e96a66cSDavid du Colombier e.gen++; 272*5e96a66cSDavid du Colombier e.dsize = 0; 273*5e96a66cSDavid du Colombier e.psize = 0; 274*5e96a66cSDavid du Colombier e.flags = 0; 275*5e96a66cSDavid du Colombier }else{ 276*5e96a66cSDavid du Colombier e.flags &= ~VtEntryLocal; 277*5e96a66cSDavid du Colombier } 278*5e96a66cSDavid du Colombier e.depth = 0; 279*5e96a66cSDavid du Colombier e.size = 0; 280*5e96a66cSDavid du Colombier e.tag = 0; 281*5e96a66cSDavid du Colombier memmove(e.score, vtZeroScore, VtScoreSize); 282*5e96a66cSDavid du Colombier entryPack(&e, b->data, r->offset % r->epb); 283*5e96a66cSDavid du Colombier blockDirty(b); 284*5e96a66cSDavid du Colombier if(addr != NilBlock) 285*5e96a66cSDavid du Colombier blockRemoveLink(b, addr, type, tag); 286*5e96a66cSDavid du Colombier blockPut(b); 287*5e96a66cSDavid du Colombier 288*5e96a66cSDavid du Colombier if(doremove){ 289*5e96a66cSDavid du Colombier sourceUnlock(r); 290*5e96a66cSDavid du Colombier sourceClose(r); 291*5e96a66cSDavid du Colombier } 292*5e96a66cSDavid du Colombier 293*5e96a66cSDavid du Colombier return 1; 294*5e96a66cSDavid du Colombier } 295*5e96a66cSDavid du Colombier 296*5e96a66cSDavid du Colombier int 297*5e96a66cSDavid du Colombier sourceRemove(Source *r) 298*5e96a66cSDavid du Colombier { 299*5e96a66cSDavid du Colombier return sourceKill(r, 1); 300*5e96a66cSDavid du Colombier } 301*5e96a66cSDavid du Colombier 302*5e96a66cSDavid du Colombier int 303*5e96a66cSDavid du Colombier sourceTruncate(Source *r) 304*5e96a66cSDavid du Colombier { 305*5e96a66cSDavid du Colombier return sourceKill(r, 0); 306*5e96a66cSDavid du Colombier } 307*5e96a66cSDavid du Colombier 308*5e96a66cSDavid du Colombier uvlong 309*5e96a66cSDavid du Colombier sourceGetSize(Source *r) 310*5e96a66cSDavid du Colombier { 311*5e96a66cSDavid du Colombier Entry e; 312*5e96a66cSDavid du Colombier Block *b; 313*5e96a66cSDavid du Colombier 314*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 315*5e96a66cSDavid du Colombier b = sourceLoad(r, &e); 316*5e96a66cSDavid du Colombier if(b == nil) 317*5e96a66cSDavid du Colombier return 0; 318*5e96a66cSDavid du Colombier blockPut(b); 319*5e96a66cSDavid du Colombier 320*5e96a66cSDavid du Colombier return e.size; 321*5e96a66cSDavid du Colombier } 322*5e96a66cSDavid du Colombier 323*5e96a66cSDavid du Colombier static int 324*5e96a66cSDavid du Colombier sourceShrinkSize(Source *r, Entry *e, uvlong size) 325*5e96a66cSDavid du Colombier { 326*5e96a66cSDavid du Colombier int i, type, ppb; 327*5e96a66cSDavid du Colombier uvlong ptrsz; 328*5e96a66cSDavid du Colombier u32int addr; 329*5e96a66cSDavid du Colombier uchar score[VtScoreSize]; 330*5e96a66cSDavid du Colombier Block *b; 331*5e96a66cSDavid du Colombier 332*5e96a66cSDavid du Colombier type = entryType(e); 333*5e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite); 334*5e96a66cSDavid du Colombier if(b == nil) 335*5e96a66cSDavid du Colombier return 0; 336*5e96a66cSDavid du Colombier 337*5e96a66cSDavid du Colombier ptrsz = e->dsize; 338*5e96a66cSDavid du Colombier ppb = e->psize/VtScoreSize; 339*5e96a66cSDavid du Colombier for(i=0; i+1<e->depth; i++) 340*5e96a66cSDavid du Colombier ptrsz *= ppb; 341*5e96a66cSDavid du Colombier 342*5e96a66cSDavid du Colombier while(type&BtLevelMask){ 343*5e96a66cSDavid du Colombier if(b->addr == NilBlock 344*5e96a66cSDavid du Colombier || (b->l.state&BsClosed) 345*5e96a66cSDavid du Colombier || b->l.epoch != r->fs->ehi){ 346*5e96a66cSDavid du Colombier /* not worth copying the block just so we can zero some of it */ 347*5e96a66cSDavid du Colombier blockPut(b); 348*5e96a66cSDavid du Colombier return 0; 349*5e96a66cSDavid du Colombier } 350*5e96a66cSDavid du Colombier 351*5e96a66cSDavid du Colombier /* 352*5e96a66cSDavid du Colombier * invariant: each pointer in the tree rooted at b accounts for ptrsz bytes 353*5e96a66cSDavid du Colombier */ 354*5e96a66cSDavid du Colombier 355*5e96a66cSDavid du Colombier /* zero the pointers to unnecessary blocks */ 356*5e96a66cSDavid du Colombier i = (size+ptrsz-1)/ptrsz; 357*5e96a66cSDavid du Colombier for(; i<ppb; i++){ 358*5e96a66cSDavid du Colombier addr = globalToLocal(b->data+i*VtScoreSize); 359*5e96a66cSDavid du Colombier memmove(b->data+i*VtScoreSize, vtZeroScore, VtScoreSize); 360*5e96a66cSDavid du Colombier blockDirty(b); 361*5e96a66cSDavid du Colombier if(addr != NilBlock) 362*5e96a66cSDavid du Colombier blockRemoveLink(b, addr, type-1, e->tag); 363*5e96a66cSDavid du Colombier } 364*5e96a66cSDavid du Colombier 365*5e96a66cSDavid du Colombier /* recurse (go around again) on the partially necessary block */ 366*5e96a66cSDavid du Colombier i = size/ptrsz; 367*5e96a66cSDavid du Colombier size = size%ptrsz; 368*5e96a66cSDavid du Colombier if(size == 0){ 369*5e96a66cSDavid du Colombier blockPut(b); 370*5e96a66cSDavid du Colombier return 1; 371*5e96a66cSDavid du Colombier } 372*5e96a66cSDavid du Colombier ptrsz /= ppb; 373*5e96a66cSDavid du Colombier type--; 374*5e96a66cSDavid du Colombier memmove(score, b->data+i*VtScoreSize, VtScoreSize); 375*5e96a66cSDavid du Colombier blockPut(b); 376*5e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, score, type, e->tag, OReadWrite); 377*5e96a66cSDavid du Colombier if(b == nil) 378*5e96a66cSDavid du Colombier return 0; 379*5e96a66cSDavid du Colombier } 380*5e96a66cSDavid du Colombier 381*5e96a66cSDavid du Colombier if(b->addr == NilBlock 382*5e96a66cSDavid du Colombier || (b->l.state&BsClosed) 383*5e96a66cSDavid du Colombier || b->l.epoch != r->fs->ehi){ 384*5e96a66cSDavid du Colombier blockPut(b); 385*5e96a66cSDavid du Colombier return 0; 386*5e96a66cSDavid du Colombier } 387*5e96a66cSDavid du Colombier 388*5e96a66cSDavid du Colombier /* 389*5e96a66cSDavid du Colombier * No one ever truncates BtDir blocks. 390*5e96a66cSDavid du Colombier */ 391*5e96a66cSDavid du Colombier if(type == BtData && e->dsize > size){ 392*5e96a66cSDavid du Colombier memset(b->data+size, 0, e->dsize-size); 393*5e96a66cSDavid du Colombier blockDirty(b); 394*5e96a66cSDavid du Colombier } 395*5e96a66cSDavid du Colombier blockPut(b); 396*5e96a66cSDavid du Colombier return 1; 397*5e96a66cSDavid du Colombier } 398*5e96a66cSDavid du Colombier 399*5e96a66cSDavid du Colombier int 400*5e96a66cSDavid du Colombier sourceSetSize(Source *r, uvlong size) 401*5e96a66cSDavid du Colombier { 402*5e96a66cSDavid du Colombier int depth; 403*5e96a66cSDavid du Colombier Entry e; 404*5e96a66cSDavid du Colombier Block *b; 405*5e96a66cSDavid du Colombier 406*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 407*5e96a66cSDavid du Colombier if(size == 0) 408*5e96a66cSDavid du Colombier return sourceTruncate(r); 409*5e96a66cSDavid du Colombier 410*5e96a66cSDavid du Colombier if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize){ 411*5e96a66cSDavid du Colombier vtSetError(ETooBig); 412*5e96a66cSDavid du Colombier return 0; 413*5e96a66cSDavid du Colombier } 414*5e96a66cSDavid du Colombier 415*5e96a66cSDavid du Colombier b = sourceLoad(r, &e); 416*5e96a66cSDavid du Colombier if(b == nil) 417*5e96a66cSDavid du Colombier return 0; 418*5e96a66cSDavid du Colombier 419*5e96a66cSDavid du Colombier /* quick out */ 420*5e96a66cSDavid du Colombier if(e.size == size){ 421*5e96a66cSDavid du Colombier blockPut(b); 422*5e96a66cSDavid du Colombier return 1; 423*5e96a66cSDavid du Colombier } 424*5e96a66cSDavid du Colombier 425*5e96a66cSDavid du Colombier depth = sizeToDepth(size, e.psize, e.dsize); 426*5e96a66cSDavid du Colombier 427*5e96a66cSDavid du Colombier if(depth < e.depth){ 428*5e96a66cSDavid du Colombier if(!sourceShrinkDepth(r, b, &e, depth)){ 429*5e96a66cSDavid du Colombier blockPut(b); 430*5e96a66cSDavid du Colombier return 0; 431*5e96a66cSDavid du Colombier } 432*5e96a66cSDavid du Colombier }else if(depth > e.depth){ 433*5e96a66cSDavid du Colombier if(!sourceGrowDepth(r, b, &e, depth)){ 434*5e96a66cSDavid du Colombier blockPut(b); 435*5e96a66cSDavid du Colombier return 0; 436*5e96a66cSDavid du Colombier } 437*5e96a66cSDavid du Colombier } 438*5e96a66cSDavid du Colombier 439*5e96a66cSDavid du Colombier if(size < e.size) 440*5e96a66cSDavid du Colombier sourceShrinkSize(r, &e, size); 441*5e96a66cSDavid du Colombier 442*5e96a66cSDavid du Colombier e.size = size; 443*5e96a66cSDavid du Colombier entryPack(&e, b->data, r->offset % r->epb); 444*5e96a66cSDavid du Colombier blockDirty(b); 445*5e96a66cSDavid du Colombier blockPut(b); 446*5e96a66cSDavid du Colombier 447*5e96a66cSDavid du Colombier return 1; 448*5e96a66cSDavid du Colombier } 449*5e96a66cSDavid du Colombier 450*5e96a66cSDavid du Colombier int 451*5e96a66cSDavid du Colombier sourceSetDirSize(Source *r, ulong ds) 452*5e96a66cSDavid du Colombier { 453*5e96a66cSDavid du Colombier uvlong size; 454*5e96a66cSDavid du Colombier int epb; 455*5e96a66cSDavid du Colombier 456*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 457*5e96a66cSDavid du Colombier epb = r->dsize/VtEntrySize; 458*5e96a66cSDavid du Colombier 459*5e96a66cSDavid du Colombier size = (uvlong)r->dsize*(ds/epb); 460*5e96a66cSDavid du Colombier size += VtEntrySize*(ds%epb); 461*5e96a66cSDavid du Colombier return sourceSetSize(r, size); 462*5e96a66cSDavid du Colombier } 463*5e96a66cSDavid du Colombier 464*5e96a66cSDavid du Colombier ulong 465*5e96a66cSDavid du Colombier sourceGetDirSize(Source *r) 466*5e96a66cSDavid du Colombier { 467*5e96a66cSDavid du Colombier ulong ds; 468*5e96a66cSDavid du Colombier uvlong size; 469*5e96a66cSDavid du Colombier int epb; 470*5e96a66cSDavid du Colombier 471*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 472*5e96a66cSDavid du Colombier epb = r->dsize/VtEntrySize; 473*5e96a66cSDavid du Colombier 474*5e96a66cSDavid du Colombier size = sourceGetSize(r); 475*5e96a66cSDavid du Colombier ds = epb*(size/r->dsize); 476*5e96a66cSDavid du Colombier ds += (size%r->dsize)/VtEntrySize; 477*5e96a66cSDavid du Colombier return ds; 478*5e96a66cSDavid du Colombier } 479*5e96a66cSDavid du Colombier 480*5e96a66cSDavid du Colombier int 481*5e96a66cSDavid du Colombier sourceGetEntry(Source *r, Entry *e) 482*5e96a66cSDavid du Colombier { 483*5e96a66cSDavid du Colombier Block *b; 484*5e96a66cSDavid du Colombier 485*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 486*5e96a66cSDavid du Colombier b = sourceLoad(r, e); 487*5e96a66cSDavid du Colombier if(b == nil) 488*5e96a66cSDavid du Colombier return 0; 489*5e96a66cSDavid du Colombier blockPut(b); 490*5e96a66cSDavid du Colombier 491*5e96a66cSDavid du Colombier return 1; 492*5e96a66cSDavid du Colombier } 493*5e96a66cSDavid du Colombier 494*5e96a66cSDavid du Colombier static Block * 495*5e96a66cSDavid du Colombier blockWalk(Block *p, int index, int mode, Fs *fs, Entry *e) 496*5e96a66cSDavid du Colombier { 497*5e96a66cSDavid du Colombier Block *b; 498*5e96a66cSDavid du Colombier Cache *c; 499*5e96a66cSDavid du Colombier u32int addr; 500*5e96a66cSDavid du Colombier int type; 501*5e96a66cSDavid du Colombier 502*5e96a66cSDavid du Colombier c = fs->cache; 503*5e96a66cSDavid du Colombier 504*5e96a66cSDavid du Colombier if((p->l.type & BtLevelMask) == 0){ 505*5e96a66cSDavid du Colombier assert(p->l.type == BtDir); 506*5e96a66cSDavid du Colombier type = entryType(e); 507*5e96a66cSDavid du Colombier b = cacheGlobal(c, e->score, type, e->tag, mode); 508*5e96a66cSDavid du Colombier }else{ 509*5e96a66cSDavid du Colombier type = p->l.type - 1; 510*5e96a66cSDavid du Colombier b = cacheGlobal(c, p->data + index*VtScoreSize, type, e->tag, mode); 511*5e96a66cSDavid du Colombier } 512*5e96a66cSDavid du Colombier 513*5e96a66cSDavid du Colombier if(b == nil || mode == OReadOnly) 514*5e96a66cSDavid du Colombier return b; 515*5e96a66cSDavid du Colombier 516*5e96a66cSDavid du Colombier assert(!(p->l.state&BsClosed) && p->l.epoch == fs->ehi); 517*5e96a66cSDavid du Colombier if(!(b->l.state&BsClosed) && b->l.epoch == fs->ehi) 518*5e96a66cSDavid du Colombier return b; 519*5e96a66cSDavid du Colombier 520*5e96a66cSDavid du Colombier /* 521*5e96a66cSDavid du Colombier * Copy on write. 522*5e96a66cSDavid du Colombier */ 523*5e96a66cSDavid du Colombier if(e->tag == 0){ 524*5e96a66cSDavid du Colombier assert(p->l.type == BtDir); 525*5e96a66cSDavid du Colombier e->tag = tagGen(); 526*5e96a66cSDavid du Colombier e->flags |= VtEntryLocal; 527*5e96a66cSDavid du Colombier } 528*5e96a66cSDavid du Colombier 529*5e96a66cSDavid du Colombier addr = b->addr; 530*5e96a66cSDavid du Colombier b = blockCopy(b, e->tag, fs->ehi, fs->elo); 531*5e96a66cSDavid du Colombier if(b == nil) 532*5e96a66cSDavid du Colombier return nil; 533*5e96a66cSDavid du Colombier 534*5e96a66cSDavid du Colombier assert(b->l.epoch == fs->ehi); 535*5e96a66cSDavid du Colombier 536*5e96a66cSDavid du Colombier if(p->l.type == BtDir){ 537*5e96a66cSDavid du Colombier memmove(e->score, b->score, VtScoreSize); 538*5e96a66cSDavid du Colombier entryPack(e, p->data, index); 539*5e96a66cSDavid du Colombier }else{ 540*5e96a66cSDavid du Colombier memmove(p->data+index*VtScoreSize, b->score, VtScoreSize); 541*5e96a66cSDavid du Colombier } 542*5e96a66cSDavid du Colombier blockDirty(b); 543*5e96a66cSDavid du Colombier blockDependency(p, b, index, b->score); 544*5e96a66cSDavid du Colombier blockDirty(p); 545*5e96a66cSDavid du Colombier 546*5e96a66cSDavid du Colombier if(addr != NilBlock) 547*5e96a66cSDavid du Colombier blockRemoveLink(p, addr, type, e->tag); 548*5e96a66cSDavid du Colombier 549*5e96a66cSDavid du Colombier return b; 550*5e96a66cSDavid du Colombier } 551*5e96a66cSDavid du Colombier 552*5e96a66cSDavid du Colombier /* 553*5e96a66cSDavid du Colombier * Change the depth of the source r. 554*5e96a66cSDavid du Colombier * The entry e for r is contained in block p. 555*5e96a66cSDavid du Colombier */ 556*5e96a66cSDavid du Colombier static int 557*5e96a66cSDavid du Colombier sourceGrowDepth(Source *r, Block *p, Entry *e, int depth) 558*5e96a66cSDavid du Colombier { 559*5e96a66cSDavid du Colombier Block *b, *bb; 560*5e96a66cSDavid du Colombier u32int tag; 561*5e96a66cSDavid du Colombier int type; 562*5e96a66cSDavid du Colombier 563*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 564*5e96a66cSDavid du Colombier assert(depth <= VtPointerDepth); 565*5e96a66cSDavid du Colombier 566*5e96a66cSDavid du Colombier type = entryType(e); 567*5e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite); 568*5e96a66cSDavid du Colombier if(b == nil) 569*5e96a66cSDavid du Colombier return 0; 570*5e96a66cSDavid du Colombier 571*5e96a66cSDavid du Colombier tag = e->tag; 572*5e96a66cSDavid du Colombier if(tag == 0) 573*5e96a66cSDavid du Colombier tag = tagGen(); 574*5e96a66cSDavid du Colombier 575*5e96a66cSDavid du Colombier /* 576*5e96a66cSDavid du Colombier * Keep adding layers until we get to the right depth 577*5e96a66cSDavid du Colombier * or an error occurs. 578*5e96a66cSDavid du Colombier */ 579*5e96a66cSDavid du Colombier while(e->depth < depth){ 580*5e96a66cSDavid du Colombier bb = cacheAllocBlock(r->fs->cache, type+1, tag, r->fs->ehi, r->fs->elo); 581*5e96a66cSDavid du Colombier if(bb == nil) 582*5e96a66cSDavid du Colombier break; 583*5e96a66cSDavid du Colombier memmove(bb->data, b->score, VtScoreSize); 584*5e96a66cSDavid du Colombier memmove(e->score, bb->score, VtScoreSize); 585*5e96a66cSDavid du Colombier e->depth++; 586*5e96a66cSDavid du Colombier type++; 587*5e96a66cSDavid du Colombier e->tag = tag; 588*5e96a66cSDavid du Colombier e->flags |= VtEntryLocal; 589*5e96a66cSDavid du Colombier blockDependency(bb, b, -1, nil); 590*5e96a66cSDavid du Colombier blockPut(b); 591*5e96a66cSDavid du Colombier blockDirty(bb); 592*5e96a66cSDavid du Colombier b = bb; 593*5e96a66cSDavid du Colombier } 594*5e96a66cSDavid du Colombier 595*5e96a66cSDavid du Colombier entryPack(e, p->data, r->offset % r->epb); 596*5e96a66cSDavid du Colombier blockDependency(p, b, -1, nil); 597*5e96a66cSDavid du Colombier blockPut(b); 598*5e96a66cSDavid du Colombier blockDirty(p); 599*5e96a66cSDavid du Colombier 600*5e96a66cSDavid du Colombier return e->depth == depth; 601*5e96a66cSDavid du Colombier } 602*5e96a66cSDavid du Colombier 603*5e96a66cSDavid du Colombier static int 604*5e96a66cSDavid du Colombier sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth) 605*5e96a66cSDavid du Colombier { 606*5e96a66cSDavid du Colombier Block *b, *nb, *ob, *rb; 607*5e96a66cSDavid du Colombier u32int tag; 608*5e96a66cSDavid du Colombier int type, d; 609*5e96a66cSDavid du Colombier 610*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 611*5e96a66cSDavid du Colombier assert(depth <= VtPointerDepth); 612*5e96a66cSDavid du Colombier 613*5e96a66cSDavid du Colombier type = entryType(e); 614*5e96a66cSDavid du Colombier rb = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite); 615*5e96a66cSDavid du Colombier if(rb == nil) 616*5e96a66cSDavid du Colombier return 0; 617*5e96a66cSDavid du Colombier 618*5e96a66cSDavid du Colombier tag = e->tag; 619*5e96a66cSDavid du Colombier if(tag == 0) 620*5e96a66cSDavid du Colombier tag = tagGen(); 621*5e96a66cSDavid du Colombier 622*5e96a66cSDavid du Colombier /* 623*5e96a66cSDavid du Colombier * Walk down to the new root block. 624*5e96a66cSDavid du Colombier * We may stop early, but something is better than nothing. 625*5e96a66cSDavid du Colombier */ 626*5e96a66cSDavid du Colombier ob = nil; 627*5e96a66cSDavid du Colombier b = rb; 628*5e96a66cSDavid du Colombier for(d=e->depth; d > depth; d--, type++){ 629*5e96a66cSDavid du Colombier nb = cacheGlobal(r->fs->cache, b->data, type-1, tag, OReadWrite); 630*5e96a66cSDavid du Colombier if(nb == nil) 631*5e96a66cSDavid du Colombier break; 632*5e96a66cSDavid du Colombier if(ob!=nil && ob!=rb) 633*5e96a66cSDavid du Colombier blockPut(ob); 634*5e96a66cSDavid du Colombier ob = b; 635*5e96a66cSDavid du Colombier b = nb; 636*5e96a66cSDavid du Colombier } 637*5e96a66cSDavid du Colombier 638*5e96a66cSDavid du Colombier if(b == rb){ 639*5e96a66cSDavid du Colombier blockPut(rb); 640*5e96a66cSDavid du Colombier return 0; 641*5e96a66cSDavid du Colombier } 642*5e96a66cSDavid du Colombier 643*5e96a66cSDavid du Colombier /* 644*5e96a66cSDavid du Colombier * Right now, e points at the root block rb, b is the new root block, 645*5e96a66cSDavid du Colombier * and ob points at b. To update: 646*5e96a66cSDavid du Colombier * 647*5e96a66cSDavid du Colombier * (i) change e to point at b 648*5e96a66cSDavid du Colombier * (ii) zero the pointer ob -> b 649*5e96a66cSDavid du Colombier * (iii) free the root block 650*5e96a66cSDavid du Colombier * 651*5e96a66cSDavid du Colombier * p (the block containing e) must be written before 652*5e96a66cSDavid du Colombier * anything else. 653*5e96a66cSDavid du Colombier */ 654*5e96a66cSDavid du Colombier 655*5e96a66cSDavid du Colombier /* (i) */ 656*5e96a66cSDavid du Colombier e->depth = d; 657*5e96a66cSDavid du Colombier memmove(e->score, b->score, VtScoreSize); 658*5e96a66cSDavid du Colombier entryPack(e, p->data, r->offset % r->epb); 659*5e96a66cSDavid du Colombier blockDirty(p); 660*5e96a66cSDavid du Colombier 661*5e96a66cSDavid du Colombier /* (ii) */ 662*5e96a66cSDavid du Colombier memmove(ob->data, vtZeroScore, VtScoreSize); 663*5e96a66cSDavid du Colombier blockDependency(ob, p, -1, nil); 664*5e96a66cSDavid du Colombier blockDirty(ob); 665*5e96a66cSDavid du Colombier 666*5e96a66cSDavid du Colombier /* (iii) */ 667*5e96a66cSDavid du Colombier if(rb->addr != NilBlock) 668*5e96a66cSDavid du Colombier blockRemoveLink(p, rb->addr, rb->l.type, rb->l.tag); 669*5e96a66cSDavid du Colombier 670*5e96a66cSDavid du Colombier blockPut(rb); 671*5e96a66cSDavid du Colombier if(ob!=nil && ob!=rb) 672*5e96a66cSDavid du Colombier blockPut(ob); 673*5e96a66cSDavid du Colombier if(b!=rb) 674*5e96a66cSDavid du Colombier blockPut(b); 675*5e96a66cSDavid du Colombier 676*5e96a66cSDavid du Colombier return d == depth; 677*5e96a66cSDavid du Colombier } 678*5e96a66cSDavid du Colombier 679*5e96a66cSDavid du Colombier Block * 680*5e96a66cSDavid du Colombier sourceBlock(Source *r, ulong bn, int mode) 681*5e96a66cSDavid du Colombier { 682*5e96a66cSDavid du Colombier Block *b, *bb; 683*5e96a66cSDavid du Colombier int index[VtPointerDepth+1]; 684*5e96a66cSDavid du Colombier Entry e; 685*5e96a66cSDavid du Colombier int i, np; 686*5e96a66cSDavid du Colombier int m; 687*5e96a66cSDavid du Colombier 688*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 689*5e96a66cSDavid du Colombier assert(bn != NilBlock); 690*5e96a66cSDavid du Colombier 691*5e96a66cSDavid du Colombier /* mode for intermediate block */ 692*5e96a66cSDavid du Colombier m = mode; 693*5e96a66cSDavid du Colombier if(m == OOverWrite) 694*5e96a66cSDavid du Colombier m = OReadWrite; 695*5e96a66cSDavid du Colombier 696*5e96a66cSDavid du Colombier b = sourceLoad(r, &e); 697*5e96a66cSDavid du Colombier if(b == nil) 698*5e96a66cSDavid du Colombier return nil; 699*5e96a66cSDavid du Colombier 700*5e96a66cSDavid du Colombier np = e.psize/VtScoreSize; 701*5e96a66cSDavid du Colombier memset(index, 0, sizeof(index)); 702*5e96a66cSDavid du Colombier for(i=0; bn > 0; i++){ 703*5e96a66cSDavid du Colombier if(i >= VtPointerDepth){ 704*5e96a66cSDavid du Colombier vtSetError(EBadAddr); 705*5e96a66cSDavid du Colombier goto Err; 706*5e96a66cSDavid du Colombier } 707*5e96a66cSDavid du Colombier index[i] = bn % np; 708*5e96a66cSDavid du Colombier bn /= np; 709*5e96a66cSDavid du Colombier } 710*5e96a66cSDavid du Colombier 711*5e96a66cSDavid du Colombier if(i > e.depth){ 712*5e96a66cSDavid du Colombier if(mode == OReadOnly){ 713*5e96a66cSDavid du Colombier vtSetError(EBadAddr); 714*5e96a66cSDavid du Colombier goto Err; 715*5e96a66cSDavid du Colombier } 716*5e96a66cSDavid du Colombier if(!sourceGrowDepth(r, b, &e, i)) 717*5e96a66cSDavid du Colombier goto Err; 718*5e96a66cSDavid du Colombier } 719*5e96a66cSDavid du Colombier 720*5e96a66cSDavid du Colombier index[e.depth] = r->offset % r->epb; 721*5e96a66cSDavid du Colombier 722*5e96a66cSDavid du Colombier for(i=e.depth; i>=0; i--){ 723*5e96a66cSDavid du Colombier bb = blockWalk(b, index[i], m, r->fs, &e); 724*5e96a66cSDavid du Colombier if(bb == nil) 725*5e96a66cSDavid du Colombier goto Err; 726*5e96a66cSDavid du Colombier blockPut(b); 727*5e96a66cSDavid du Colombier b = bb; 728*5e96a66cSDavid du Colombier } 729*5e96a66cSDavid du Colombier return b; 730*5e96a66cSDavid du Colombier Err: 731*5e96a66cSDavid du Colombier blockPut(b); 732*5e96a66cSDavid du Colombier return nil; 733*5e96a66cSDavid du Colombier } 734*5e96a66cSDavid du Colombier 735*5e96a66cSDavid du Colombier void 736*5e96a66cSDavid du Colombier sourceClose(Source *r) 737*5e96a66cSDavid du Colombier { 738*5e96a66cSDavid du Colombier if(r == nil) 739*5e96a66cSDavid du Colombier return; 740*5e96a66cSDavid du Colombier vtLock(r->lk); 741*5e96a66cSDavid du Colombier r->ref--; 742*5e96a66cSDavid du Colombier if(r->ref){ 743*5e96a66cSDavid du Colombier vtUnlock(r->lk); 744*5e96a66cSDavid du Colombier return; 745*5e96a66cSDavid du Colombier } 746*5e96a66cSDavid du Colombier assert(r->ref == 0); 747*5e96a66cSDavid du Colombier vtUnlock(r->lk); 748*5e96a66cSDavid du Colombier if(r->parent) 749*5e96a66cSDavid du Colombier sourceClose(r->parent); 750*5e96a66cSDavid du Colombier vtLockFree(r->lk); 751*5e96a66cSDavid du Colombier memset(r, ~0, sizeof(*r)); 752*5e96a66cSDavid du Colombier vtMemFree(r); 753*5e96a66cSDavid du Colombier } 754*5e96a66cSDavid du Colombier 755*5e96a66cSDavid du Colombier /* 756*5e96a66cSDavid du Colombier * Retrieve the block containing the entry for r. 757*5e96a66cSDavid du Colombier * If a snapshot has happened, we might need 758*5e96a66cSDavid du Colombier * to get a new copy of the block. We avoid this 759*5e96a66cSDavid du Colombier * in the common case by caching the score for 760*5e96a66cSDavid du Colombier * the block and the last epoch in which it was valid. 761*5e96a66cSDavid du Colombier * 762*5e96a66cSDavid du Colombier * We use r->mode to tell the difference between active 763*5e96a66cSDavid du Colombier * file system sources (OReadWrite) and sources for the 764*5e96a66cSDavid du Colombier * snapshot file system (OReadOnly). 765*5e96a66cSDavid du Colombier */ 766*5e96a66cSDavid du Colombier static Block* 767*5e96a66cSDavid du Colombier sourceLoadBlock(Source *r, int mode) 768*5e96a66cSDavid du Colombier { 769*5e96a66cSDavid du Colombier u32int addr; 770*5e96a66cSDavid du Colombier Block *b; 771*5e96a66cSDavid du Colombier 772*5e96a66cSDavid du Colombier switch(r->mode){ 773*5e96a66cSDavid du Colombier default: 774*5e96a66cSDavid du Colombier assert(0); 775*5e96a66cSDavid du Colombier case OReadWrite: 776*5e96a66cSDavid du Colombier assert(r->mode == OReadWrite); 777*5e96a66cSDavid du Colombier assert(r->epoch >= r->fs->elo); 778*5e96a66cSDavid du Colombier if(r->epoch == r->fs->ehi){ 779*5e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite); 780*5e96a66cSDavid du Colombier assert(r->epoch == b->l.epoch); 781*5e96a66cSDavid du Colombier if(b == nil) 782*5e96a66cSDavid du Colombier return nil; 783*5e96a66cSDavid du Colombier return b; 784*5e96a66cSDavid du Colombier } 785*5e96a66cSDavid du Colombier assert(r->parent != nil); 786*5e96a66cSDavid du Colombier if(!sourceLock(r->parent, OReadWrite)) 787*5e96a66cSDavid du Colombier return nil; 788*5e96a66cSDavid du Colombier b = sourceBlock(r->parent, r->offset/r->epb, OReadWrite); 789*5e96a66cSDavid du Colombier sourceUnlock(r->parent); 790*5e96a66cSDavid du Colombier if(b == nil) 791*5e96a66cSDavid du Colombier return nil; 792*5e96a66cSDavid du Colombier assert(b->l.epoch == r->fs->ehi); 793*5e96a66cSDavid du Colombier memmove(r->score, b->score, VtScoreSize); 794*5e96a66cSDavid du Colombier r->scoreEpoch = b->l.epoch; 795*5e96a66cSDavid du Colombier r->tag = b->l.tag; 796*5e96a66cSDavid du Colombier r->epoch = r->fs->ehi; 797*5e96a66cSDavid du Colombier return b; 798*5e96a66cSDavid du Colombier 799*5e96a66cSDavid du Colombier case OReadOnly: 800*5e96a66cSDavid du Colombier addr = globalToLocal(r->score); 801*5e96a66cSDavid du Colombier if(addr == NilBlock) 802*5e96a66cSDavid du Colombier return cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, mode); 803*5e96a66cSDavid du Colombier 804*5e96a66cSDavid du Colombier b = cacheLocalData(r->fs->cache, addr, BtDir, r->tag, mode, r->scoreEpoch); 805*5e96a66cSDavid du Colombier if(b) 806*5e96a66cSDavid du Colombier return b; 807*5e96a66cSDavid du Colombier 808*5e96a66cSDavid du Colombier /* 809*5e96a66cSDavid du Colombier * If it failed because the epochs don't match, the block has been 810*5e96a66cSDavid du Colombier * archived and reclaimed. Rewalk from the parent and get the 811*5e96a66cSDavid du Colombier * new pointer. This can't happen in the OReadWrite case 812*5e96a66cSDavid du Colombier * above because blocks in the current epoch don't get 813*5e96a66cSDavid du Colombier * reclaimed. The fact that we're OReadOnly means we're 814*5e96a66cSDavid du Colombier * a snapshot. (Or else the file system is read-only, but then 815*5e96a66cSDavid du Colombier * the archiver isn't going around deleting blocks.) 816*5e96a66cSDavid du Colombier */ 817*5e96a66cSDavid du Colombier if(strcmp(vtGetError(), ELabelMismatch) == 0){ 818*5e96a66cSDavid du Colombier if(!sourceLock(r->parent, OReadOnly)) 819*5e96a66cSDavid du Colombier return nil; 820*5e96a66cSDavid du Colombier b = sourceBlock(r->parent, r->offset/r->epb, OReadOnly); 821*5e96a66cSDavid du Colombier sourceUnlock(r->parent); 822*5e96a66cSDavid du Colombier if(b){ 823*5e96a66cSDavid du Colombier fprint(2, "sourceAlloc: lost %V found %V\n", 824*5e96a66cSDavid du Colombier r->score, b->score); 825*5e96a66cSDavid du Colombier memmove(r->score, b->score, VtScoreSize); 826*5e96a66cSDavid du Colombier r->scoreEpoch = b->l.epoch; 827*5e96a66cSDavid du Colombier return b; 828*5e96a66cSDavid du Colombier } 829*5e96a66cSDavid du Colombier } 830*5e96a66cSDavid du Colombier return nil; 831*5e96a66cSDavid du Colombier } 832*5e96a66cSDavid du Colombier } 833*5e96a66cSDavid du Colombier 834*5e96a66cSDavid du Colombier int 835*5e96a66cSDavid du Colombier sourceLock(Source *r, int mode) 836*5e96a66cSDavid du Colombier { 837*5e96a66cSDavid du Colombier Block *b; 838*5e96a66cSDavid du Colombier 839*5e96a66cSDavid du Colombier if(mode == -1) 840*5e96a66cSDavid du Colombier mode = r->mode; 841*5e96a66cSDavid du Colombier 842*5e96a66cSDavid du Colombier b = sourceLoadBlock(r, mode); 843*5e96a66cSDavid du Colombier if(b == nil) 844*5e96a66cSDavid du Colombier return 0; 845*5e96a66cSDavid du Colombier /* 846*5e96a66cSDavid du Colombier * The fact that we are holding b serves as the 847*5e96a66cSDavid du Colombier * lock entitling us to write to r->b. 848*5e96a66cSDavid du Colombier */ 849*5e96a66cSDavid du Colombier assert(r->b == nil); 850*5e96a66cSDavid du Colombier r->b = b; 851*5e96a66cSDavid du Colombier if(r->mode == OReadWrite) 852*5e96a66cSDavid du Colombier assert(r->epoch == r->b->l.epoch); 853*5e96a66cSDavid du Colombier return 1; 854*5e96a66cSDavid du Colombier } 855*5e96a66cSDavid du Colombier 856*5e96a66cSDavid du Colombier /* 857*5e96a66cSDavid du Colombier * Lock two (usually sibling) sources. This needs special care 858*5e96a66cSDavid du Colombier * because the Entries for both sources might be in the same block. 859*5e96a66cSDavid du Colombier * We also try to lock blocks in left-to-right order within the tree. 860*5e96a66cSDavid du Colombier */ 861*5e96a66cSDavid du Colombier int 862*5e96a66cSDavid du Colombier sourceLock2(Source *r, Source *rr, int mode) 863*5e96a66cSDavid du Colombier { 864*5e96a66cSDavid du Colombier Block *b, *bb; 865*5e96a66cSDavid du Colombier 866*5e96a66cSDavid du Colombier if(rr == nil) 867*5e96a66cSDavid du Colombier return sourceLock(r, mode); 868*5e96a66cSDavid du Colombier 869*5e96a66cSDavid du Colombier if(mode == -1) 870*5e96a66cSDavid du Colombier mode = r->mode; 871*5e96a66cSDavid du Colombier 872*5e96a66cSDavid du Colombier if(r->parent==rr->parent && r->offset/r->epb == rr->offset/rr->epb){ 873*5e96a66cSDavid du Colombier b = sourceLoadBlock(r, mode); 874*5e96a66cSDavid du Colombier if(b == nil) 875*5e96a66cSDavid du Colombier return 0; 876*5e96a66cSDavid du Colombier blockDupLock(b); 877*5e96a66cSDavid du Colombier bb = b; 878*5e96a66cSDavid du Colombier }else if(r->parent==rr->parent || r->offset > rr->offset){ 879*5e96a66cSDavid du Colombier bb = sourceLoadBlock(rr, mode); 880*5e96a66cSDavid du Colombier b = sourceLoadBlock(r, mode); 881*5e96a66cSDavid du Colombier }else{ 882*5e96a66cSDavid du Colombier b = sourceLoadBlock(r, mode); 883*5e96a66cSDavid du Colombier bb = sourceLoadBlock(rr, mode); 884*5e96a66cSDavid du Colombier } 885*5e96a66cSDavid du Colombier if(b == nil || bb == nil){ 886*5e96a66cSDavid du Colombier if(b) 887*5e96a66cSDavid du Colombier blockPut(b); 888*5e96a66cSDavid du Colombier if(bb) 889*5e96a66cSDavid du Colombier blockPut(bb); 890*5e96a66cSDavid du Colombier return 0; 891*5e96a66cSDavid du Colombier } 892*5e96a66cSDavid du Colombier 893*5e96a66cSDavid du Colombier /* 894*5e96a66cSDavid du Colombier * The fact that we are holding b and bb serves 895*5e96a66cSDavid du Colombier * as the lock entitling us to write to r->b and rr->b. 896*5e96a66cSDavid du Colombier */ 897*5e96a66cSDavid du Colombier r->b = b; 898*5e96a66cSDavid du Colombier rr->b = bb; 899*5e96a66cSDavid du Colombier return 1; 900*5e96a66cSDavid du Colombier } 901*5e96a66cSDavid du Colombier 902*5e96a66cSDavid du Colombier void 903*5e96a66cSDavid du Colombier sourceUnlock(Source *r) 904*5e96a66cSDavid du Colombier { 905*5e96a66cSDavid du Colombier Block *b; 906*5e96a66cSDavid du Colombier 907*5e96a66cSDavid du Colombier if(r->b == nil){ 908*5e96a66cSDavid du Colombier fprint(2, "sourceUnlock: already unlocked\n"); 909*5e96a66cSDavid du Colombier abort(); 910*5e96a66cSDavid du Colombier } 911*5e96a66cSDavid du Colombier b = r->b; 912*5e96a66cSDavid du Colombier r->b = nil; 913*5e96a66cSDavid du Colombier blockPut(b); 914*5e96a66cSDavid du Colombier } 915*5e96a66cSDavid du Colombier 916*5e96a66cSDavid du Colombier static Block* 917*5e96a66cSDavid du Colombier sourceLoad(Source *r, Entry *e) 918*5e96a66cSDavid du Colombier { 919*5e96a66cSDavid du Colombier Block *b; 920*5e96a66cSDavid du Colombier 921*5e96a66cSDavid du Colombier assert(sourceIsLocked(r)); 922*5e96a66cSDavid du Colombier b = r->b; 923*5e96a66cSDavid du Colombier if(!entryUnpack(e, b->data, r->offset % r->epb)) 924*5e96a66cSDavid du Colombier return nil; 925*5e96a66cSDavid du Colombier if(e->gen != r->gen){ 926*5e96a66cSDavid du Colombier vtSetError(ERemoved); 927*5e96a66cSDavid du Colombier return nil; 928*5e96a66cSDavid du Colombier } 929*5e96a66cSDavid du Colombier blockDupLock(b); 930*5e96a66cSDavid du Colombier return b; 931*5e96a66cSDavid du Colombier } 932*5e96a66cSDavid du Colombier 933*5e96a66cSDavid du Colombier static int 934*5e96a66cSDavid du Colombier sizeToDepth(uvlong s, int psize, int dsize) 935*5e96a66cSDavid du Colombier { 936*5e96a66cSDavid du Colombier int np; 937*5e96a66cSDavid du Colombier int d; 938*5e96a66cSDavid du Colombier 939*5e96a66cSDavid du Colombier /* determine pointer depth */ 940*5e96a66cSDavid du Colombier np = psize/VtScoreSize; 941*5e96a66cSDavid du Colombier s = (s + dsize - 1)/dsize; 942*5e96a66cSDavid du Colombier for(d = 0; s > 1; d++) 943*5e96a66cSDavid du Colombier s = (s + np - 1)/np; 944*5e96a66cSDavid du Colombier return d; 945*5e96a66cSDavid du Colombier } 946*5e96a66cSDavid du Colombier 947*5e96a66cSDavid du Colombier static u32int 948*5e96a66cSDavid du Colombier tagGen(void) 949*5e96a66cSDavid du Colombier { 950*5e96a66cSDavid du Colombier u32int tag; 951*5e96a66cSDavid du Colombier 952*5e96a66cSDavid du Colombier for(;;){ 953*5e96a66cSDavid du Colombier tag = lrand(); 954*5e96a66cSDavid du Colombier if(tag >= UserTag) 955*5e96a66cSDavid du Colombier break; 956*5e96a66cSDavid du Colombier } 957*5e96a66cSDavid du Colombier return tag; 958*5e96a66cSDavid du Colombier } 959