source.c 20 KB

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