flchk.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. #include "stdinc.h"
  2. #include "dat.h"
  3. #include "fns.h"
  4. typedef struct MetaChunk MetaChunk;
  5. struct MetaChunk {
  6. ushort offset;
  7. ushort size;
  8. ushort index;
  9. };
  10. static void usage(void);
  11. static void setBit(uchar *bmap, ulong addr);
  12. static int getBit(uchar *bmap, ulong addr);
  13. static int readLabel(Label *l, u32int addr);
  14. static void error(char*, ...);
  15. static void warn(char *fmt, ...);
  16. static void chkEpoch(u32int epoch);
  17. static void chkFree(void);
  18. static int readLabel(Label *l, u32int addr);
  19. static void chkDir(char *name, Source *source, Source *meta);
  20. #pragma varargck argpos error 1
  21. #pragma varargck argpos warn 1
  22. uchar *amap; /* bitmap: has been visited at all */
  23. uchar *emap; /* bitmap: see condition (ii) below */
  24. uchar *vmap; /* bitmap: has been visited in this epoch */
  25. uchar *xmap; /* bitmap: see condition (iii) below */
  26. Fs *fs;
  27. Cache *cache;
  28. int nblocks;
  29. int bsize;
  30. int badactive;
  31. int dumpblocks; /* write lost blocks into /tmp/lost */
  32. int fast; /* don't check that all the venti blocks are there */
  33. u32int hint; /* a guess at where chkEpoch might look to find the next root */
  34. void
  35. main(int argc, char *argv[])
  36. {
  37. int csize = 1000;
  38. VtSession *z;
  39. char *host = nil;
  40. u32int e;
  41. Source *r, *mr;
  42. Block *b;
  43. Super super;
  44. ARGBEGIN{
  45. default:
  46. usage();
  47. case 'c':
  48. csize = atoi(ARGF());
  49. if(csize <= 0)
  50. usage();
  51. break;
  52. case 'd':
  53. dumpblocks = 1;
  54. break;
  55. case 'f':
  56. fast = 1;
  57. break;
  58. case 'h':
  59. host = ARGF();
  60. break;
  61. }ARGEND;
  62. if(argc != 1)
  63. usage();
  64. vtAttach();
  65. fmtinstall('L', labelFmt);
  66. fmtinstall('V', scoreFmt);
  67. fmtinstall('R', vtErrFmt);
  68. /*
  69. * Connect to Venti.
  70. */
  71. z = vtDial(host, 0);
  72. if(z == nil){
  73. if(!fast)
  74. vtFatal("could not connect to server: %s", vtGetError());
  75. }else if(!vtConnect(z, 0))
  76. vtFatal("vtConnect: %s", vtGetError());
  77. /*
  78. * Initialize file system.
  79. */
  80. fs = fsOpen(argv[0], z, csize, OReadOnly);
  81. if(fs == nil)
  82. vtFatal("could not open file system: %R");
  83. cache = fs->cache;
  84. nblocks = cacheLocalSize(cache, PartData);
  85. bsize = fs->blockSize;
  86. b = superGet(cache, &super);
  87. if(b == nil)
  88. vtFatal("could not load super block: %R");
  89. blockPut(b);
  90. hint = super.active;
  91. /*
  92. * Run checks.
  93. */
  94. amap = vtMemAllocZ(nblocks/8 + 1);
  95. emap = vtMemAllocZ(nblocks/8 + 1);
  96. vmap = vtMemAllocZ(nblocks/8 + 1);
  97. xmap = vtMemAllocZ(nblocks/8 + 1);
  98. for(e=fs->ehi; e >= fs->elo; e--){
  99. memset(emap, 0, nblocks/8+1);
  100. memset(xmap, 0, nblocks/8+1);
  101. chkEpoch(e);
  102. }
  103. chkFree();
  104. vtMemFree(amap);
  105. vtMemFree(emap);
  106. vtMemFree(vmap);
  107. vtMemFree(xmap);
  108. sourceLock(fs->source, OReadOnly);
  109. r = sourceOpen(fs->source, 0, OReadOnly);
  110. mr = sourceOpen(fs->source, 1, OReadOnly);
  111. sourceUnlock(fs->source);
  112. chkDir("", r, mr);
  113. sourceClose(r);
  114. sourceClose(mr);
  115. fsClose(fs);
  116. exits(0);
  117. }
  118. static void
  119. usage(void)
  120. {
  121. fprint(2, "usage: %s [-c cachesize] [-h host] file\n", argv0);
  122. exits("usage");
  123. }
  124. /*
  125. * When b points at bb, need to check:
  126. *
  127. * (i) b.e in [bb.e, bb.eClose)
  128. * (ii) if b.e==bb.e, then no other b' in e points at bb.
  129. * (iii) if !(b.state&Copied) and b.e==bb.e then no other b' points at bb.
  130. * (iv) if b is active then no other active b' points at bb.
  131. * (v) if b is a past life of b' then only one of b and b' is active (too hard to check)
  132. *
  133. * Does not walk onto Venti.
  134. */
  135. static int
  136. walk(Block *b, uchar score[VtScoreSize], int type, u32int tag, u32int epoch)
  137. {
  138. Block *bb;
  139. u32int addr;
  140. int i, ret;
  141. u32int ep;
  142. Entry e;
  143. if(fast && globalToLocal(score) == NilBlock)
  144. return 1;
  145. bb = cacheGlobal(cache, score, type, tag, OReadOnly);
  146. if(bb == nil){
  147. error("could not load block %V type %d tag %ux: %R", score, type, tag);
  148. return 0;
  149. }
  150. ret = 0;
  151. addr = globalToLocal(score);
  152. if(addr == NilBlock){
  153. ret = 1;
  154. goto Exit;
  155. }
  156. /* (i) */
  157. if(b->l.epoch < bb->l.epoch || bb->l.epochClose <= b->l.epoch){
  158. error("walk: block %#ux [%ud, %ud) points at %#ux [%ud, %ud)\n",
  159. b->addr, b->l.epoch, b->l.epochClose,
  160. bb->addr, bb->l.epoch, bb->l.epochClose);
  161. goto Exit;
  162. }
  163. /* (ii) */
  164. if(b->l.epoch == epoch && bb->l.epoch == epoch){
  165. if(getBit(emap, addr)){
  166. error("walk: epoch join detected: addr %#ux %L\n", bb->addr, &bb->l);
  167. goto Exit;
  168. }
  169. setBit(emap, addr);
  170. }
  171. /* (iii) */
  172. if(!(b->l.state&BsCopied) && b->l.epoch == bb->l.epoch){
  173. if(getBit(xmap, addr)){
  174. error("walk: copy join detected; addr %#ux %L\n", bb->addr, &bb->l);
  175. goto Exit;
  176. }
  177. setBit(xmap, addr);
  178. }
  179. /* (iv) */
  180. if(epoch == fs->ehi){
  181. /* since epoch==fs->ehi is first, amap is same as ``have seen active'' */
  182. if(getBit(amap, addr)){
  183. error("walk: active join detected: addr %#ux %L\n", bb->addr, &bb->l);
  184. goto Exit;
  185. }
  186. }
  187. if(getBit(vmap, addr)){
  188. ret = 1;
  189. goto Exit;
  190. }
  191. setBit(vmap, addr);
  192. setBit(amap, addr);
  193. b = nil; /* make sure no more refs to parent */
  194. USED(b);
  195. switch(type){
  196. default:
  197. /* pointer block */
  198. for(i=0; i<bsize/VtScoreSize; i++)
  199. if(!walk(bb, bb->data + i*VtScoreSize, type-1, tag, epoch))
  200. print("# clrp %#ux %d\n", bb->addr, i);
  201. break;
  202. case BtData:
  203. break;
  204. case BtDir:
  205. for(i=0; i<bsize/VtEntrySize; i++){
  206. if(!entryUnpack(&e, bb->data, i)){
  207. error("walk: could not unpack entry: %ux[%d]: %R", addr, i);
  208. print("# clre %#ux %d\n", bb->addr, i);
  209. continue;
  210. }
  211. if(!(e.flags & VtEntryActive))
  212. continue;
  213. //fprint(2, "%x[%d] tag=%x snap=%d score=%V\n", addr, i, e.tag, e.snap, e.score);
  214. ep = epoch;
  215. if(e.snap != 0){
  216. if(e.snap >= epoch){
  217. error("bad snap in entry: %ux[%d] snap = %ud: epoch = %ud",
  218. addr, i, e.snap, epoch);
  219. print("# clre %#ux %d\n", bb->addr, i);
  220. continue;
  221. }
  222. continue;
  223. }
  224. if(e.flags & VtEntryLocal){
  225. if(e.tag < UserTag)
  226. if(e.tag != RootTag || tag != RootTag || i != 1){
  227. error("bad tag in entry: %ux[%d] tag = %ux", addr, i, e.tag);
  228. print("# clre %#ux %d\n", bb->addr, i);
  229. continue;
  230. }
  231. }else{
  232. if(e.tag != 0){
  233. error("bad tag in entry: %ux[%d] tag = %ux", addr, i, e.tag);
  234. print("# clre %#ux %d\n", bb->addr, i);
  235. continue;
  236. }
  237. }
  238. if(!walk(bb, e.score, entryType(&e), e.tag, ep))
  239. print("# clre %#ux %d\n", bb->addr, i);
  240. }
  241. break;
  242. }
  243. ret = 1;
  244. Exit:
  245. blockPut(bb);
  246. return ret;
  247. }
  248. static void
  249. chkEpoch(u32int epoch)
  250. {
  251. u32int a;
  252. Label l;
  253. Entry e;
  254. Block *b;
  255. print("chkEpoch %ud\n", epoch);
  256. /* find root block */
  257. for(a=0; a<nblocks; a++){
  258. if(!readLabel(&l, (a+hint)%nblocks)){
  259. error("could not read label: addr %ux %d %ux %ux: %R", a, l.type, l.state, l.state);
  260. continue;
  261. }
  262. if(l.tag == RootTag && l.epoch == epoch)
  263. break;
  264. }
  265. if(a == nblocks){
  266. print("chkEpoch: could not find root block for epoch: %ud\n", epoch);
  267. return;
  268. }
  269. a = (a+hint)%nblocks;
  270. b = cacheLocalData(cache, a, BtDir, RootTag, OReadOnly, 0);
  271. if(b == nil){
  272. error("could not read root block %ux: %R\n", a);
  273. return;
  274. }
  275. /* no one should point at the root blocks */
  276. setBit(amap, a);
  277. setBit(emap, a);
  278. setBit(vmap, a);
  279. setBit(xmap, a);
  280. /*
  281. * First entry is the rest of the file system.
  282. * Second entry is link to previous epoch root,
  283. * just a convenience to help the search.
  284. */
  285. if(!entryUnpack(&e, b->data, 0)){
  286. error("could not unpack root block %ux: %R", a);
  287. blockPut(b);
  288. return;
  289. }
  290. walk(b, e.score, BtDir, e.tag, epoch);
  291. if(entryUnpack(&e, b->data, 1))
  292. hint = globalToLocal(e.score);
  293. blockPut(b);
  294. }
  295. /*
  296. * We've just walked the whole write buffer. Notice blocks that
  297. * aren't marked available but that we didn't visit. They are lost.
  298. */
  299. static void
  300. chkFree(void)
  301. {
  302. char buf[64];
  303. int fd;
  304. u32int a;
  305. Block *b;
  306. Label l;
  307. u32int nfree;
  308. u32int nlost;
  309. nfree = 0;
  310. nlost = 0;
  311. /* find root block */
  312. for(a=0; a<nblocks; a++){
  313. if(!readLabel(&l, a)){
  314. error("could not read label: addr %ux %d %d: %R",
  315. a, l.type, l.state);
  316. continue;
  317. }
  318. if(getBit(amap, a))
  319. continue;
  320. if(l.state == BsFree || l.epochClose <= fs->elo){
  321. nfree++;
  322. setBit(amap, a);
  323. continue;
  324. }
  325. nlost++;
  326. warn("unreachable block: addr %ux type %d tag %ux state %s epoch %ud close %ud",
  327. a, l.type, l.tag, bsStr(l.state), l.epoch, l.epochClose);
  328. print("# bfree %#ux\n", a);
  329. if(dumpblocks){
  330. sprint(buf, "/tmp/lost.%ux", a);
  331. if((fd = create(buf, OWRITE, 0666)) < 0){
  332. fprint(2, "create %s: %r\n", buf);
  333. goto nodump;
  334. }
  335. if((b = cacheLocal(cache, PartData, a, OReadOnly)) == nil){
  336. close(fd);
  337. fprint(2, "load block %ux: %R\n", a);
  338. goto nodump;
  339. }
  340. if(write(fd, b->data, bsize) != bsize)
  341. fprint(2, "writiting %s: %r\n", buf);
  342. close(fd);
  343. blockPut(b);
  344. }
  345. nodump:
  346. setBit(amap, a);
  347. }
  348. fprint(2, "\tused=%ud free space = %ud(%f%%) lost=%ud\n",
  349. nblocks-nfree-nlost, nblocks, 100.*nfree/nblocks, nlost);
  350. }
  351. static Source *
  352. openSource(Source *s, char *name, uchar *bm, u32int offset, u32int gen, int dir)
  353. {
  354. Source *r;
  355. if(getBit(bm, offset)){
  356. warn("multiple references to source: %s -> %d", name, offset);
  357. print("# clri %s\n", name);
  358. return nil;
  359. }
  360. setBit(bm, offset);
  361. r = sourceOpen(s, offset, OReadOnly);
  362. if(r == nil){
  363. warn("could not open source: %s -> %d: %R", name, offset);
  364. print("# clri %s\n", name);
  365. return nil;
  366. }
  367. if(r->gen != gen){
  368. warn("source has been removed: %s -> %d", name, offset);
  369. print("# clri %s\n", name);
  370. goto Err;
  371. }
  372. if(r->dir != dir){
  373. warn("dir mismatch: %s -> %d", name, offset);
  374. print("# clri %s\n", name);
  375. goto Err;
  376. }
  377. return r;
  378. Err:
  379. sourceClose(r);
  380. return nil;
  381. }
  382. static int
  383. offsetCmp(void *s0, void *s1)
  384. {
  385. MetaChunk *mc0, *mc1;
  386. mc0 = s0;
  387. mc1 = s1;
  388. if(mc0->offset < mc1->offset)
  389. return -1;
  390. if(mc0->offset > mc1->offset)
  391. return 1;
  392. return 0;
  393. }
  394. /*
  395. * Check that MetaBlock has reasonable header, sorted entries,
  396. */
  397. int
  398. chkMetaBlock(MetaBlock *mb)
  399. {
  400. MetaChunk *mc;
  401. int oo, o, n, i;
  402. uchar *p;
  403. mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk));
  404. p = mb->buf + MetaHeaderSize;
  405. for(i = 0; i<mb->nindex; i++){
  406. mc[i].offset = (p[0]<<8) | p[1];
  407. mc[i].size = (p[2]<<8) | p[3];
  408. mc[i].index = i;
  409. p += MetaIndexSize;
  410. }
  411. qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);
  412. /* check block looks ok */
  413. oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  414. o = oo;
  415. n = 0;
  416. for(i=0; i<mb->nindex; i++){
  417. o = mc[i].offset;
  418. n = mc[i].size;
  419. if(o < oo)
  420. goto Err;
  421. oo += n;
  422. }
  423. if(o+n > mb->size)
  424. goto Err;
  425. if(mb->size - oo != mb->free)
  426. goto Err;
  427. vtMemFree(mc);
  428. return 1;
  429. Err:
  430. fprint(2, "metaChunks failed!\n");
  431. oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  432. for(i=0; i<mb->nindex; i++){
  433. fprint(2, "\t%d: %d %d\n", i, mc[i].offset, mc[i].offset + mc[i].size);
  434. oo += mc[i].size;
  435. }
  436. fprint(2, "\tused=%d size=%d free=%d free2=%d\n", oo, mb->size, mb->free, mb->size - oo);
  437. vtMemFree(mc);
  438. return 0;
  439. }
  440. /*
  441. * Walk the source tree making sure that the BtData
  442. * sources containing directory entries are okay.
  443. *
  444. * Walks onto Venti, so takes a long time.
  445. */
  446. static void
  447. chkDir(char *name, Source *source, Source *meta)
  448. {
  449. uchar *bm;
  450. Block *b, *bb;
  451. u32int nb, o;
  452. MetaBlock mb;
  453. DirEntry de;
  454. MetaEntry me;
  455. int i;
  456. char *s, *nn;
  457. Source *r, *mr;
  458. if(fast && globalToLocal(source->score)==NilBlock && globalToLocal(meta->score)==NilBlock)
  459. return;
  460. if(!sourceLock2(source, meta, OReadOnly)){
  461. warn("could not lock sources for %s: %R", name);
  462. return;
  463. }
  464. bm = vtMemAllocZ(sourceGetDirSize(source)/8 + 1);
  465. nb = (sourceGetSize(meta) + meta->dsize - 1)/meta->dsize;
  466. for(o=0; o<nb; o++){
  467. b = sourceBlock(meta, o, OReadOnly);
  468. if(0)fprint(2, "source %V:%d block %d addr %d\n", source->score, source->offset, o, b->addr);
  469. if(b == nil){
  470. error("could not read block in meta file: %s[%ud]: %R", name, o);
  471. continue;
  472. }
  473. if(!mbUnpack(&mb, b->data, meta->dsize)){
  474. error("could not unpack meta block: %s[%ud]: %R", name, o);
  475. blockPut(b);
  476. continue;
  477. }
  478. if(!chkMetaBlock(&mb)){
  479. error("bad meta block: %s[%ud]: %R", name, o);
  480. blockPut(b);
  481. continue;
  482. }
  483. s = vtStrDup("");
  484. for(i=0; i<mb.nindex; i++){
  485. meUnpack(&me, &mb, i);
  486. if(!deUnpack(&de, &me)){
  487. error("cound not unpack dir entry: %s[%ud][%d]: %R", name, o, i);
  488. continue;
  489. }
  490. if(strcmp(s, de.elem) >= 0)
  491. error("dir entry out of order: %s[%ud][%d] = %s last = %s", name, o, i,
  492. de.elem, s);
  493. vtMemFree(s);
  494. s = vtStrDup(de.elem);
  495. nn = smprint("%s/%s", name, de.elem);
  496. if(!(de.mode & ModeDir)){
  497. r = openSource(source, nn, bm, de.entry, de.gen, 0);
  498. if(r != nil)
  499. sourceClose(r);
  500. deCleanup(&de);
  501. free(nn);
  502. continue;
  503. }
  504. r = openSource(source, nn, bm, de.entry, de.gen, 1);
  505. if(r == nil){
  506. deCleanup(&de);
  507. free(nn);
  508. continue;
  509. }
  510. mr = openSource(source, nn, bm, de.mentry, de.mgen, 0);
  511. if(mr == nil){
  512. sourceClose(r);
  513. deCleanup(&de);
  514. free(nn);
  515. continue;
  516. }
  517. chkDir(nn, r, mr);
  518. sourceClose(mr);
  519. sourceClose(r);
  520. deCleanup(&de);
  521. free(nn);
  522. deCleanup(&de);
  523. }
  524. vtMemFree(s);
  525. blockPut(b);
  526. }
  527. nb = sourceGetDirSize(source);
  528. for(o=0; o<nb; o++){
  529. if(getBit(bm, o))
  530. continue;
  531. r = sourceOpen(source, o, OReadOnly);
  532. if(r == nil)
  533. continue;
  534. warn("non referenced entry in source %s[%d]", name, o);
  535. if((bb = sourceBlock(source, o/(source->dsize/VtEntrySize), OReadOnly)) != nil){
  536. if(bb->addr != NilBlock)
  537. print("# clre %#ux %d\n", bb->addr, o%(source->dsize/VtEntrySize));
  538. blockPut(bb);
  539. }
  540. sourceClose(r);
  541. }
  542. sourceUnlock(source);
  543. sourceUnlock(meta);
  544. vtMemFree(bm);
  545. }
  546. static void
  547. setBit(uchar *bmap, ulong addr)
  548. {
  549. bmap[addr>>3] |= 1 << (addr & 7);
  550. }
  551. static int
  552. getBit(uchar *bmap, ulong addr)
  553. {
  554. return (bmap[addr>>3] >> (addr & 7)) & 1;
  555. }
  556. static int
  557. readLabel(Label *l, u32int addr)
  558. {
  559. int lpb;
  560. Block *b;
  561. u32int a;
  562. lpb = bsize / LabelSize;
  563. a = addr / lpb;
  564. b = cacheLocal(cache, PartLabel, a, OReadOnly);
  565. if(b == nil){
  566. blockPut(b);
  567. return 0;
  568. }
  569. if(!labelUnpack(l, b->data, addr%lpb)){
  570. print("labelUnpack %ux failed\n", addr);
  571. blockPut(b);
  572. return 0;
  573. }
  574. blockPut(b);
  575. return 1;
  576. }
  577. static void
  578. error(char *fmt, ...)
  579. {
  580. static nerr;
  581. va_list arg;
  582. char buf[128];
  583. va_start(arg, fmt);
  584. vseprint(buf, buf+sizeof(buf), fmt, arg);
  585. va_end(arg);
  586. print("error: %s\n", buf);
  587. // if(nerr++ > 20)
  588. // vtFatal("too many errors");
  589. }
  590. static void
  591. warn(char *fmt, ...)
  592. {
  593. static nerr;
  594. va_list arg;
  595. char buf[128];
  596. va_start(arg, fmt);
  597. vseprint(buf, buf+sizeof(buf), fmt, arg);
  598. va_end(arg);
  599. print("warn: %s\n", buf);
  600. }