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