check.c 18 KB

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