check.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. #include "stdinc.h"
  2. #include "dat.h"
  3. #include "fns.h"
  4. static void checkDirs(Fsck*);
  5. static void checkEpochs(Fsck*);
  6. static void checkLeak(Fsck*);
  7. static void closenop(Fsck*, Block*, u32int);
  8. static void clrenop(Fsck*, Block*, int);
  9. static void clrinop(Fsck*, char*, MetaBlock*, int, Block*);
  10. static void error(Fsck*, char*, ...);
  11. static int getBit(uchar*, u32int);
  12. static int printnop(char*, ...);
  13. static void setBit(uchar*, u32int);
  14. static int walkEpoch(Fsck *chk, Block *b, uchar score[VtScoreSize],
  15. int type, u32int tag, u32int epoch);
  16. static void warn(Fsck*, char*, ...);
  17. #pragma varargck argpos error 2
  18. #pragma varargck argpos printnop 1
  19. #pragma varargck argpos warn 2
  20. static Fsck*
  21. checkInit(Fsck *chk)
  22. {
  23. chk->cache = chk->fs->cache;
  24. chk->nblocks = cacheLocalSize(chk->cache, PartData);;
  25. chk->bsize = chk->fs->blockSize;
  26. chk->walkdepth = 0;
  27. chk->hint = 0;
  28. chk->quantum = chk->nblocks/100;
  29. if(chk->quantum == 0)
  30. chk->quantum = 1;
  31. if(chk->print == nil)
  32. chk->print = printnop;
  33. if(chk->clre == nil)
  34. chk->clre = clrenop;
  35. if(chk->close == nil)
  36. chk->close = closenop;
  37. if(chk->clri == nil)
  38. chk->clri = clrinop;
  39. return chk;
  40. }
  41. /*
  42. * BUG: Should merge checkEpochs and checkDirs so that
  43. * bad blocks are only reported once, and so that errors in checkEpochs
  44. * can have the affected file names attached, and so that the file system
  45. * is only read once.
  46. *
  47. * Also should summarize the errors instead of printing for every one
  48. * (e.g., XXX bad or unreachable blocks in /active/usr/rsc/foo).
  49. */
  50. void
  51. fsCheck(Fsck *chk)
  52. {
  53. Block *b;
  54. Super super;
  55. checkInit(chk);
  56. b = superGet(chk->cache, &super);
  57. if(b == nil){
  58. chk->print("could not load super block: %R");
  59. return;
  60. }
  61. blockPut(b);
  62. chk->hint = super.active;
  63. checkEpochs(chk);
  64. chk->smap = vtMemAllocZ(chk->nblocks/8+1);
  65. checkDirs(chk);
  66. vtMemFree(chk->smap);
  67. }
  68. static void checkEpoch(Fsck*, u32int);
  69. /*
  70. * Walk through all the blocks in the write buffer.
  71. * Then we can look for ones we missed -- those are leaks.
  72. */
  73. static void
  74. checkEpochs(Fsck *chk)
  75. {
  76. u32int e;
  77. uint nb;
  78. nb = chk->nblocks;
  79. chk->amap = vtMemAllocZ(nb/8+1);
  80. chk->emap = vtMemAllocZ(nb/8+1);
  81. chk->xmap = vtMemAllocZ(nb/8+1);
  82. chk->errmap = vtMemAllocZ(nb/8+1);
  83. for(e = chk->fs->ehi; e >= chk->fs->elo; e--){
  84. memset(chk->emap, 0, chk->nblocks/8+1);
  85. memset(chk->xmap, 0, chk->nblocks/8+1);
  86. checkEpoch(chk, e);
  87. }
  88. checkLeak(chk);
  89. vtMemFree(chk->amap);
  90. vtMemFree(chk->emap);
  91. vtMemFree(chk->xmap);
  92. vtMemFree(chk->errmap);
  93. }
  94. static void
  95. checkEpoch(Fsck *chk, u32int epoch)
  96. {
  97. u32int a;
  98. Block *b;
  99. Entry e;
  100. Label l;
  101. chk->print("checking epoch %ud...\n", epoch);
  102. for(a=0; a<chk->nblocks; a++){
  103. if(!readLabel(chk->cache, &l, (a+chk->hint)%chk->nblocks)){
  104. error(chk, "could not read label for addr 0x%.8#ux", a);
  105. continue;
  106. }
  107. if(l.tag == RootTag && l.epoch == epoch)
  108. break;
  109. }
  110. if(a == chk->nblocks){
  111. chk->print("could not find root block for epoch %ud", epoch);
  112. return;
  113. }
  114. a = (a+chk->hint)%chk->nblocks;
  115. b = cacheLocalData(chk->cache, a, BtDir, RootTag, OReadOnly, 0);
  116. if(b == nil){
  117. error(chk, "could not read root block 0x%.8#ux: %R", a);
  118. return;
  119. }
  120. /* no one should point at root blocks */
  121. setBit(chk->amap, a);
  122. setBit(chk->emap, a);
  123. setBit(chk->xmap, a);
  124. /*
  125. * First entry is the rest of the file system.
  126. * Second entry is link to previous epoch root,
  127. * just a convenience to help the search.
  128. */
  129. if(!entryUnpack(&e, b->data, 0)){
  130. error(chk, "could not unpack root block 0x%.8#ux: %R", a);
  131. blockPut(b);
  132. return;
  133. }
  134. walkEpoch(chk, b, e.score, BtDir, e.tag, epoch);
  135. if(entryUnpack(&e, b->data, 1))
  136. chk->hint = globalToLocal(e.score);
  137. blockPut(b);
  138. }
  139. /*
  140. * When b points at bb, need to check:
  141. *
  142. * (i) b.e in [bb.e, bb.eClose)
  143. * (ii) if b.e==bb.e, then no other b' in e points at bb.
  144. * (iii) if !(b.state&Copied) and b.e==bb.e then no other b' points at bb.
  145. * (iv) if b is active then no other active b' points at bb.
  146. * (v) if b is a past life of b' then only one of b and b' is active
  147. * (too hard to check)
  148. */
  149. static int
  150. walkEpoch(Fsck *chk, Block *b, uchar score[VtScoreSize], int type, u32int tag,
  151. u32int epoch)
  152. {
  153. int i, ret;
  154. u32int addr, ep;
  155. Block *bb;
  156. Entry e;
  157. if(b && chk->walkdepth == 0 && chk->printblocks)
  158. chk->print("%V %d %#.8ux %#.8ux\n", b->score, b->l.type,
  159. b->l.tag, b->l.epoch);
  160. if(!chk->useventi && globalToLocal(score) == NilBlock)
  161. return 1;
  162. chk->walkdepth++;
  163. bb = cacheGlobal(chk->cache, score, type, tag, OReadOnly);
  164. if(bb == nil){
  165. error(chk, "could not load block %V type %d tag %ux: %R",
  166. score, type, tag);
  167. chk->walkdepth--;
  168. return 0;
  169. }
  170. if(chk->printblocks)
  171. chk->print("%*s%V %d %#.8ux %#.8ux\n", chk->walkdepth*2, "",
  172. score, type, tag, bb->l.epoch);
  173. ret = 0;
  174. addr = globalToLocal(score);
  175. if(addr == NilBlock){
  176. ret = 1;
  177. goto Exit;
  178. }
  179. if(b){
  180. /* (i) */
  181. if(b->l.epoch < bb->l.epoch || bb->l.epochClose <= b->l.epoch){
  182. error(chk, "walk: block %#ux [%ud, %ud) points at %#ux [%ud, %ud)",
  183. b->addr, b->l.epoch, b->l.epochClose,
  184. bb->addr, bb->l.epoch, bb->l.epochClose);
  185. goto Exit;
  186. }
  187. /* (ii) */
  188. if(b->l.epoch == epoch && bb->l.epoch == epoch){
  189. if(getBit(chk->emap, addr)){
  190. error(chk, "walk: epoch join detected: addr %#ux %L",
  191. bb->addr, &bb->l);
  192. goto Exit;
  193. }
  194. setBit(chk->emap, addr);
  195. }
  196. /* (iii) */
  197. if(!(b->l.state&BsCopied) && b->l.epoch == bb->l.epoch){
  198. if(getBit(chk->xmap, addr)){
  199. error(chk, "walk: copy join detected; addr %#ux %L",
  200. bb->addr, &bb->l);
  201. goto Exit;
  202. }
  203. setBit(chk->xmap, addr);
  204. }
  205. }
  206. /* (iv) */
  207. if(epoch == chk->fs->ehi){
  208. /*
  209. * since epoch==fs->ehi is first, amap is same as
  210. * ``have seen active''
  211. */
  212. if(getBit(chk->amap, addr)){
  213. error(chk, "walk: active join detected: addr %#ux %L",
  214. bb->addr, &bb->l);
  215. goto Exit;
  216. }
  217. if(bb->l.state&BsClosed)
  218. error(chk, "walk: addr %#ux: block is in active tree but is closed",
  219. addr);
  220. }else
  221. if(!getBit(chk->amap, addr))
  222. if(!(bb->l.state&BsClosed)){
  223. // error(chk, "walk: addr %#ux: block is not in active tree, not closed (%d)",
  224. // addr, bb->l.epochClose);
  225. chk->close(chk, bb, epoch+1);
  226. chk->nclose++;
  227. }
  228. if(getBit(chk->amap, addr)){
  229. ret = 1;
  230. goto Exit;
  231. }
  232. setBit(chk->amap, addr);
  233. if(chk->nseen++%chk->quantum == 0)
  234. chk->print("check: visited %d/%d blocks (%.0f%%)\n",
  235. chk->nseen, chk->nblocks, chk->nseen*100./chk->nblocks);
  236. b = nil; /* make sure no more refs to parent */
  237. USED(b);
  238. switch(type){
  239. default:
  240. /* pointer block */
  241. for(i = 0; i < chk->bsize/VtScoreSize; i++)
  242. if(!walkEpoch(chk, bb, bb->data + i*VtScoreSize,
  243. type-1, tag, epoch)){
  244. setBit(chk->errmap, bb->addr);
  245. chk->clrp(chk, bb, i);
  246. chk->nclrp++;
  247. }
  248. break;
  249. case BtData:
  250. break;
  251. case BtDir:
  252. for(i = 0; i < chk->bsize/VtEntrySize; i++){
  253. if(!entryUnpack(&e, bb->data, i)){
  254. // error(chk, "walk: could not unpack entry: %ux[%d]: %R",
  255. // addr, i);
  256. setBit(chk->errmap, bb->addr);
  257. chk->clre(chk, bb, i);
  258. chk->nclre++;
  259. continue;
  260. }
  261. if(!(e.flags & VtEntryActive))
  262. continue;
  263. if(0) fprint(2, "%x[%d] tag=%x snap=%d score=%V\n",
  264. addr, i, e.tag, e.snap, e.score);
  265. ep = epoch;
  266. if(e.snap != 0){
  267. if(e.snap >= epoch){
  268. // error(chk, "bad snap in entry: %ux[%d] snap = %ud: epoch = %ud",
  269. // addr, i, e.snap, epoch);
  270. setBit(chk->errmap, bb->addr);
  271. chk->clre(chk, bb, i);
  272. chk->nclre++;
  273. continue;
  274. }
  275. continue;
  276. }
  277. if(e.flags & VtEntryLocal){
  278. if(e.tag < UserTag)
  279. if(e.tag != RootTag || tag != RootTag || i != 1){
  280. // error(chk, "bad tag in entry: %ux[%d] tag = %ux",
  281. // addr, i, e.tag);
  282. setBit(chk->errmap, bb->addr);
  283. chk->clre(chk, bb, i);
  284. chk->nclre++;
  285. continue;
  286. }
  287. }else
  288. if(e.tag != 0){
  289. // error(chk, "bad tag in entry: %ux[%d] tag = %ux",
  290. // addr, i, e.tag);
  291. setBit(chk->errmap, bb->addr);
  292. chk->clre(chk, bb, i);
  293. chk->nclre++;
  294. continue;
  295. }
  296. if(!walkEpoch(chk, bb, e.score, entryType(&e),
  297. e.tag, ep)){
  298. setBit(chk->errmap, bb->addr);
  299. chk->clre(chk, bb, i);
  300. chk->nclre++;
  301. }
  302. }
  303. break;
  304. }
  305. ret = 1;
  306. Exit:
  307. chk->walkdepth--;
  308. blockPut(bb);
  309. return ret;
  310. }
  311. /*
  312. * We've just walked the whole write buffer. Notice blocks that
  313. * aren't marked available but that we didn't visit. They are lost.
  314. */
  315. static void
  316. checkLeak(Fsck *chk)
  317. {
  318. u32int a, nfree, nlost;
  319. Block *b;
  320. Label l;
  321. nfree = 0;
  322. nlost = 0;
  323. for(a = 0; a < chk->nblocks; a++){
  324. if(!readLabel(chk->cache, &l, a)){
  325. error(chk, "could not read label: addr 0x%ux %d %d: %R",
  326. a, l.type, l.state);
  327. continue;
  328. }
  329. if(getBit(chk->amap, a))
  330. continue;
  331. if(l.state == BsFree || l.epochClose <= chk->fs->elo ||
  332. l.epochClose == l.epoch){
  333. nfree++;
  334. setBit(chk->amap, a);
  335. continue;
  336. }
  337. if(l.state&BsClosed)
  338. continue;
  339. nlost++;
  340. // warn(chk, "unreachable block: addr 0x%ux type %d tag 0x%ux "
  341. // "state %s epoch %ud close %ud", a, l.type, l.tag,
  342. // bsStr(l.state), l.epoch, l.epochClose);
  343. b = cacheLocal(chk->cache, PartData, a, OReadOnly);
  344. if(b == nil){
  345. error(chk, "could not read block 0x%#.8ux", a);
  346. continue;
  347. }
  348. chk->close(chk, b, 0);
  349. chk->nclose++;
  350. setBit(chk->amap, a);
  351. blockPut(b);
  352. }
  353. chk->print("fsys blocks: total=%ud used=%ud(%.1f%%) free=%ud(%.1f%%) lost=%ud(%.1f%%)\n",
  354. chk->nblocks,
  355. chk->nblocks - nfree-nlost,
  356. 100.*(chk->nblocks - nfree - nlost)/chk->nblocks,
  357. nfree, 100.*nfree/chk->nblocks,
  358. nlost, 100.*nlost/chk->nblocks);
  359. }
  360. /*
  361. * Check that all sources in the tree are accessible.
  362. */
  363. static Source *
  364. openSource(Fsck *chk, Source *s, char *name, uchar *bm, u32int offset,
  365. u32int gen, int dir, MetaBlock *mb, int i, Block *b)
  366. {
  367. Source *r;
  368. r = nil;
  369. if(getBit(bm, offset)){
  370. warn(chk, "multiple references to source: %s -> %d",
  371. name, offset);
  372. goto Err;
  373. }
  374. setBit(bm, offset);
  375. r = sourceOpen(s, offset, OReadOnly, 0);
  376. if(r == nil){
  377. warn(chk, "could not open source: %s -> %d: %R", name, offset);
  378. goto Err;
  379. }
  380. if(r->gen != gen){
  381. warn(chk, "source has been removed: %s -> %d", name, offset);
  382. goto Err;
  383. }
  384. if(r->dir != dir){
  385. warn(chk, "dir mismatch: %s -> %d", name, offset);
  386. goto Err;
  387. }
  388. return r;
  389. Err:
  390. chk->clri(chk, name, mb, i, b);
  391. chk->nclri++;
  392. if(r)
  393. sourceClose(r);
  394. return nil;
  395. }
  396. typedef struct MetaChunk MetaChunk;
  397. struct MetaChunk {
  398. ushort offset;
  399. ushort size;
  400. ushort index;
  401. };
  402. static int
  403. offsetCmp(void *s0, void *s1)
  404. {
  405. MetaChunk *mc0, *mc1;
  406. mc0 = s0;
  407. mc1 = s1;
  408. if(mc0->offset < mc1->offset)
  409. return -1;
  410. if(mc0->offset > mc1->offset)
  411. return 1;
  412. return 0;
  413. }
  414. /*
  415. * Fsck that MetaBlock has reasonable header, sorted entries,
  416. */
  417. static int
  418. chkMetaBlock(MetaBlock *mb)
  419. {
  420. MetaChunk *mc;
  421. int oo, o, n, i;
  422. uchar *p;
  423. mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk));
  424. p = mb->buf + MetaHeaderSize;
  425. for(i = 0; i < mb->nindex; i++){
  426. mc[i].offset = p[0]<<8 | p[1];
  427. mc[i].size = p[2]<<8 | p[3];
  428. mc[i].index = i;
  429. p += MetaIndexSize;
  430. }
  431. qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);
  432. /* check block looks ok */
  433. oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  434. o = oo;
  435. n = 0;
  436. for(i = 0; i < mb->nindex; i++){
  437. o = mc[i].offset;
  438. n = mc[i].size;
  439. if(o < oo)
  440. goto Err;
  441. oo += n;
  442. }
  443. if(o+n > mb->size || mb->size - oo != mb->free)
  444. goto Err;
  445. vtMemFree(mc);
  446. return 1;
  447. Err:
  448. if(0){
  449. fprint(2, "metaChunks failed!\n");
  450. oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  451. for(i=0; i<mb->nindex; i++){
  452. fprint(2, "\t%d: %d %d\n", i, mc[i].offset,
  453. mc[i].offset + mc[i].size);
  454. oo += mc[i].size;
  455. }
  456. fprint(2, "\tused=%d size=%d free=%d free2=%d\n",
  457. oo, mb->size, mb->free, mb->size - oo);
  458. }
  459. vtMemFree(mc);
  460. return 0;
  461. }
  462. static void
  463. scanSource(Fsck *chk, char *name, Source *r)
  464. {
  465. u32int a, nb, o;
  466. Block *b;
  467. Entry e;
  468. if(!chk->useventi && globalToLocal(r->score)==NilBlock)
  469. return;
  470. if(!sourceGetEntry(r, &e)){
  471. error(chk, "could not get entry for %s", name);
  472. return;
  473. }
  474. a = globalToLocal(e.score);
  475. if(!chk->useventi && a==NilBlock)
  476. return;
  477. if(getBit(chk->smap, a))
  478. return;
  479. setBit(chk->smap, a);
  480. nb = (sourceGetSize(r) + r->dsize-1) / r->dsize;
  481. for(o = 0; o < nb; o++){
  482. b = sourceBlock(r, o, OReadOnly);
  483. if(b == nil){
  484. error(chk, "could not read block in data file %s", name);
  485. continue;
  486. }
  487. if(b->addr != NilBlock && getBit(chk->errmap, b->addr)){
  488. warn(chk, "previously reported error in block %ux is in file %s",
  489. b->addr, name);
  490. }
  491. blockPut(b);
  492. }
  493. }
  494. /*
  495. * Walk the source tree making sure that the BtData
  496. * sources containing directory entries are okay.
  497. */
  498. static void
  499. chkDir(Fsck *chk, char *name, Source *source, Source *meta)
  500. {
  501. int i;
  502. u32int a1, a2, nb, o;
  503. char *s, *nn;
  504. uchar *bm;
  505. Block *b, *bb;
  506. DirEntry de;
  507. Entry e1, e2;
  508. MetaBlock mb;
  509. MetaEntry me;
  510. Source *r, *mr;
  511. if(!chk->useventi && globalToLocal(source->score)==NilBlock &&
  512. globalToLocal(meta->score)==NilBlock)
  513. return;
  514. if(!sourceLock2(source, meta, OReadOnly)){
  515. warn(chk, "could not lock sources for %s: %R", name);
  516. return;
  517. }
  518. if(!sourceGetEntry(source, &e1) || !sourceGetEntry(meta, &e2)){
  519. warn(chk, "could not load entries for %s: %R", name);
  520. return;
  521. }
  522. a1 = globalToLocal(e1.score);
  523. a2 = globalToLocal(e2.score);
  524. if((!chk->useventi && a1==NilBlock && a2==NilBlock)
  525. || (getBit(chk->smap, a1) && getBit(chk->smap, a2))){
  526. sourceUnlock(source);
  527. sourceUnlock(meta);
  528. return;
  529. }
  530. setBit(chk->smap, a1);
  531. setBit(chk->smap, a2);
  532. bm = vtMemAllocZ(sourceGetDirSize(source)/8 + 1);
  533. nb = (sourceGetSize(meta) + meta->dsize - 1)/meta->dsize;
  534. for(o = 0; o < nb; o++){
  535. b = sourceBlock(meta, o, OReadOnly);
  536. if(b == nil){
  537. error(chk, "could not read block in meta file: %s[%ud]: %R",
  538. name, o);
  539. continue;
  540. }
  541. if(0) fprint(2, "source %V:%d block %d addr %d\n", source->score,
  542. source->offset, o, b->addr);
  543. if(b->addr != NilBlock && getBit(chk->errmap, b->addr))
  544. warn(chk, "previously reported error in block %ux is in %s",
  545. b->addr, name);
  546. if(!mbUnpack(&mb, b->data, meta->dsize)){
  547. error(chk, "could not unpack meta block: %s[%ud]: %R",
  548. name, o);
  549. blockPut(b);
  550. continue;
  551. }
  552. if(!chkMetaBlock(&mb)){
  553. error(chk, "bad meta block: %s[%ud]: %R", name, o);
  554. blockPut(b);
  555. continue;
  556. }
  557. s = nil;
  558. for(i=mb.nindex-1; i>=0; i--){
  559. meUnpack(&me, &mb, i);
  560. if(!deUnpack(&de, &me)){
  561. error(chk,
  562. "could not unpack dir entry: %s[%ud][%d]: %R",
  563. name, o, i);
  564. continue;
  565. }
  566. if(s && strcmp(s, de.elem) <= 0)
  567. error(chk,
  568. "dir entry out of order: %s[%ud][%d] = %s last = %s",
  569. name, o, i, de.elem, s);
  570. vtMemFree(s);
  571. s = vtStrDup(de.elem);
  572. nn = smprint("%s/%s", name, de.elem);
  573. if(nn == nil){
  574. error(chk, "out of memory");
  575. continue;
  576. }
  577. if(chk->printdirs)
  578. if(de.mode&ModeDir)
  579. chk->print("%s/\n", nn);
  580. if(chk->printfiles)
  581. if(!(de.mode&ModeDir))
  582. chk->print("%s\n", nn);
  583. if(!(de.mode & ModeDir)){
  584. r = openSource(chk, source, nn, bm, de.entry,
  585. de.gen, 0, &mb, i, b);
  586. if(r != nil){
  587. if(sourceLock(r, OReadOnly)){
  588. scanSource(chk, nn, r);
  589. sourceUnlock(r);
  590. }
  591. sourceClose(r);
  592. }
  593. deCleanup(&de);
  594. free(nn);
  595. continue;
  596. }
  597. r = openSource(chk, source, nn, bm, de.entry,
  598. de.gen, 1, &mb, i, b);
  599. if(r == nil){
  600. deCleanup(&de);
  601. free(nn);
  602. continue;
  603. }
  604. mr = openSource(chk, source, nn, bm, de.mentry,
  605. de.mgen, 0, &mb, i, b);
  606. if(mr == nil){
  607. sourceClose(r);
  608. deCleanup(&de);
  609. free(nn);
  610. continue;
  611. }
  612. if(!(de.mode&ModeSnapshot) || chk->walksnapshots)
  613. chkDir(chk, nn, r, mr);
  614. sourceClose(mr);
  615. sourceClose(r);
  616. deCleanup(&de);
  617. free(nn);
  618. deCleanup(&de);
  619. }
  620. vtMemFree(s);
  621. blockPut(b);
  622. }
  623. nb = sourceGetDirSize(source);
  624. for(o=0; o<nb; o++){
  625. if(getBit(bm, o))
  626. continue;
  627. r = sourceOpen(source, o, OReadOnly, 0);
  628. if(r == nil)
  629. continue;
  630. warn(chk, "non referenced entry in source %s[%d]", name, o);
  631. if((bb = sourceBlock(source, o/(source->dsize/VtEntrySize),
  632. OReadOnly)) != nil){
  633. if(bb->addr != NilBlock){
  634. setBit(chk->errmap, bb->addr);
  635. chk->clre(chk, bb, o%(source->dsize/VtEntrySize));
  636. chk->nclre++;
  637. }
  638. blockPut(bb);
  639. }
  640. sourceClose(r);
  641. }
  642. sourceUnlock(source);
  643. sourceUnlock(meta);
  644. vtMemFree(bm);
  645. }
  646. static void
  647. checkDirs(Fsck *chk)
  648. {
  649. Source *r, *mr;
  650. sourceLock(chk->fs->source, OReadOnly);
  651. r = sourceOpen(chk->fs->source, 0, OReadOnly, 0);
  652. mr = sourceOpen(chk->fs->source, 1, OReadOnly, 0);
  653. sourceUnlock(chk->fs->source);
  654. chkDir(chk, "", r, mr);
  655. sourceClose(r);
  656. sourceClose(mr);
  657. }
  658. static void
  659. setBit(uchar *bmap, u32int addr)
  660. {
  661. if(addr == NilBlock)
  662. return;
  663. bmap[addr>>3] |= 1 << (addr & 7);
  664. }
  665. static int
  666. getBit(uchar *bmap, u32int addr)
  667. {
  668. if(addr == NilBlock)
  669. return 0;
  670. return (bmap[addr>>3] >> (addr & 7)) & 1;
  671. }
  672. static void
  673. error(Fsck *chk, char *fmt, ...)
  674. {
  675. char buf[256];
  676. va_list arg;
  677. static int nerr;
  678. va_start(arg, fmt);
  679. vseprint(buf, buf+sizeof buf, fmt, arg);
  680. va_end(arg);
  681. chk->print("error: %s\n", buf);
  682. // if(nerr++ > 20)
  683. // vtFatal("too many errors");
  684. }
  685. static void
  686. warn(Fsck *chk, char *fmt, ...)
  687. {
  688. char buf[256];
  689. va_list arg;
  690. static int nerr;
  691. va_start(arg, fmt);
  692. vseprint(buf, buf+sizeof buf, fmt, arg);
  693. va_end(arg);
  694. chk->print("error: %s\n", buf);
  695. }
  696. static void
  697. clrenop(Fsck*, Block*, int)
  698. {
  699. }
  700. static void
  701. closenop(Fsck*, Block*, u32int)
  702. {
  703. }
  704. static void
  705. clrinop(Fsck*, char*, MetaBlock*, int, Block*)
  706. {
  707. }
  708. static int
  709. printnop(char*, ...)
  710. {
  711. return 0;
  712. }