chk.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  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 "all.h"
  10. /* augmented Dentry */
  11. typedef struct {
  12. Dentry *d;
  13. Off qpath;
  14. int ns;
  15. } Extdentry;
  16. static char* abits;
  17. static int32_t sizabits;
  18. static char* qbits;
  19. static int32_t sizqbits;
  20. static char* name;
  21. static int32_t sizname;
  22. static Off fstart;
  23. static Off fsize;
  24. static Off nfiles;
  25. static Off maxq;
  26. static Device* dev;
  27. static Off ndup;
  28. static Off nused;
  29. static Off nfdup;
  30. static Off nqbad;
  31. static Off nfree;
  32. static Off nbad;
  33. static int mod;
  34. static int flags;
  35. static int ronly;
  36. static int cwflag;
  37. static Devsize sbaddr;
  38. static Devsize oldblock;
  39. static int depth;
  40. static int maxdepth;
  41. static uint8_t *lowstack, *startstack;
  42. /* local prototypes */
  43. static int amark(Off);
  44. static void* chkalloc(ulong);
  45. static void ckfreelist(Superb*);
  46. static int fmark(Off);
  47. static int fsck(Dentry*);
  48. static int ftest(Off);
  49. static Dentry* maked(Off, int, Off);
  50. static void missing(void);
  51. static void mkfreelist(Superb*);
  52. static void modd(Off, int, Dentry*);
  53. static void qmark(Off);
  54. static void trfreelist(Superb*);
  55. static void xaddfree(Device*, Off, Superb*, Iobuf*);
  56. static void xflush(Device*, Superb*, Iobuf*);
  57. static void xread(Off, Off);
  58. static Iobuf* xtag(Off, int, Off);
  59. static void *
  60. chkalloc(uint32_t n)
  61. {
  62. char *p = mallocz(n, 1);
  63. if (p == nil)
  64. panic("chkalloc: out of memory");
  65. return p;
  66. }
  67. void
  68. chkfree(void *p)
  69. {
  70. free(p);
  71. }
  72. /*
  73. * check flags
  74. */
  75. enum
  76. {
  77. Crdall = (1<<0), /* read all files */
  78. Ctag = (1<<1), /* rebuild tags */
  79. Cpfile = (1<<2), /* print files */
  80. Cpdir = (1<<3), /* print directories */
  81. Cfree = (1<<4), /* rebuild free list */
  82. // Csetqid = (1<<5), /* resequence qids */
  83. Cream = (1<<6), /* clear all bad tags */
  84. Cbad = (1<<7), /* clear all bad blocks */
  85. Ctouch = (1<<8), /* touch old dir and indir */
  86. Ctrim = (1<<9), /* trim fsize back to fit when checking free list */
  87. };
  88. static struct {
  89. char* option;
  90. int32_t flag;
  91. } ckoption[] = {
  92. "rdall", Crdall,
  93. "tag", Ctag,
  94. "pfile", Cpfile,
  95. "pdir", Cpdir,
  96. "free", Cfree,
  97. // "setqid", Csetqid,
  98. "ream", Cream,
  99. "bad", Cbad,
  100. "touch", Ctouch,
  101. "trim", Ctrim,
  102. 0,
  103. };
  104. void
  105. cmd_check(int argc, char *argv[])
  106. {
  107. int32_t f, i, flag;
  108. Off raddr;
  109. Filsys *fs;
  110. Iobuf *p;
  111. Superb *sb;
  112. Dentry *d;
  113. flag = 0;
  114. for(i=1; i<argc; i++) {
  115. for(f=0; ckoption[f].option; f++)
  116. if(strcmp(argv[i], ckoption[f].option) == 0)
  117. goto found;
  118. print("unknown check option %s\n", argv[i]);
  119. for(f=0; ckoption[f].option; f++)
  120. print("\t%s\n", ckoption[f].option);
  121. return;
  122. found:
  123. flag |= ckoption[f].flag;
  124. }
  125. fs = cons.curfs;
  126. dev = fs->dev;
  127. ronly = (dev->type == Devro);
  128. cwflag = (dev->type == Devcw) | (dev->type == Devro);
  129. if(!ronly)
  130. wlock(&mainlock); /* check */
  131. flags = flag;
  132. name = abits = qbits = nil; /* in case of goto */
  133. sbaddr = superaddr(dev);
  134. raddr = getraddr(dev);
  135. p = xtag(sbaddr, Tsuper, QPSUPER);
  136. if(!p)
  137. goto out;
  138. sb = (Superb*)p->iobuf;
  139. fstart = 2;
  140. cons.noage = 1;
  141. /* 200 is slop since qidgen is likely to be a little bit low */
  142. sizqbits = (sb->qidgen+200 + 7) / 8;
  143. qbits = chkalloc(sizqbits);
  144. fsize = sb->fsize;
  145. sizabits = (fsize-fstart + 7)/8;
  146. abits = chkalloc(sizabits);
  147. sizname = 4000;
  148. name = chkalloc(sizname);
  149. sizname -= NAMELEN+10; /* for safety */
  150. mod = 0;
  151. nfree = 0;
  152. nfdup = 0;
  153. nused = 0;
  154. nbad = 0;
  155. ndup = 0;
  156. nqbad = 0;
  157. depth = 0;
  158. maxdepth = 0;
  159. if(flags & Ctouch) {
  160. /* round fsize down to start of current side */
  161. int s;
  162. Devsize dsize;
  163. oldblock = 0;
  164. for (s = 0; dsize = wormsizeside(dev, s),
  165. dsize > 0 && oldblock + dsize < fsize; s++)
  166. oldblock += dsize;
  167. print("oldblock = %lld\n", (Wideoff)oldblock);
  168. }
  169. amark(sbaddr);
  170. if(cwflag) {
  171. amark(sb->roraddr);
  172. amark(sb->next);
  173. }
  174. print("checking filsys: %s\n", fs->name);
  175. nfiles = 0;
  176. maxq = 0;
  177. d = maked(raddr, 0, QPROOT);
  178. if(d) {
  179. amark(raddr);
  180. if(fsck(d))
  181. modd(raddr, 0, d);
  182. chkfree(d);
  183. depth--;
  184. if(depth)
  185. print("depth not zero on return\n");
  186. }
  187. if(flags & Cfree)
  188. if(cwflag)
  189. trfreelist(sb);
  190. else
  191. mkfreelist(sb);
  192. if(sb->qidgen < maxq)
  193. print("qid generator low path=%lld maxq=%lld\n",
  194. (Wideoff)sb->qidgen, (Wideoff)maxq);
  195. if(!(flags & Cfree))
  196. ckfreelist(sb);
  197. if(mod) {
  198. sb->qidgen = maxq;
  199. print("file system was modified\n");
  200. settag(p, Tsuper, QPNONE);
  201. }
  202. print("nfiles = %lld\n", (Wideoff)nfiles);
  203. print("fsize = %lld\n", (Wideoff)fsize);
  204. print("nused = %lld\n", (Wideoff)nused);
  205. print("ndup = %lld\n", (Wideoff)ndup);
  206. print("nfree = %lld\n", (Wideoff)nfree);
  207. print("tfree = %lld\n", (Wideoff)sb->tfree);
  208. print("nfdup = %lld\n", (Wideoff)nfdup);
  209. print("nmiss = %lld\n", (Wideoff)fsize-fstart-nused-nfree);
  210. print("nbad = %lld\n", (Wideoff)nbad);
  211. print("nqbad = %lld\n", (Wideoff)nqbad);
  212. print("maxq = %lld\n", (Wideoff)maxq);
  213. print("base stack=%llu\n", (int64_t)startstack);
  214. /* high-water mark of stack usage */
  215. print("high stack=%llu\n", (int64_t)lowstack);
  216. print("deepest recursion=%d\n", maxdepth-1); /* one-origin */
  217. if(!cwflag)
  218. missing();
  219. out:
  220. cons.noage = 0;
  221. putbuf(p);
  222. chkfree(name);
  223. chkfree(abits);
  224. chkfree(qbits);
  225. name = abits = qbits = nil;
  226. if(!ronly)
  227. wunlock(&mainlock);
  228. }
  229. /*
  230. * if *blkp is already allocated and Cbad is set, zero it.
  231. * returns *blkp if it's free, else 0.
  232. */
  233. static Off
  234. blkck(Off *blkp, int *flgp)
  235. {
  236. Off a = *blkp;
  237. if(amark(a)) {
  238. if(flags & Cbad) {
  239. *blkp = 0;
  240. *flgp |= Bmod;
  241. }
  242. a = 0;
  243. }
  244. return a;
  245. }
  246. /*
  247. * if a block address within a Dentry, *blkp, is already allocated
  248. * and Cbad is set, zero it.
  249. * stores 0 into *resp if already allocated, else stores *blkp.
  250. * returns dmod count.
  251. */
  252. static int
  253. daddrck(Off *blkp, Off *resp)
  254. {
  255. int dmod = 0;
  256. if(amark(*blkp)) {
  257. if(flags & Cbad) {
  258. *blkp = 0;
  259. dmod++;
  260. }
  261. *resp = 0;
  262. } else
  263. *resp = *blkp;
  264. return dmod;
  265. }
  266. /*
  267. * under Ctouch, read block `a' if it's in range.
  268. * returns dmod count.
  269. */
  270. static int
  271. touch(Off a)
  272. {
  273. if((flags&Ctouch) && a < oldblock) {
  274. Iobuf *pd = getbuf(dev, a, Brd|Bmod);
  275. if(pd)
  276. putbuf(pd);
  277. return 1;
  278. }
  279. return 0;
  280. }
  281. /*
  282. * if d is a directory, touch it and check all its entries in block a.
  283. * if not, under Crdall, read a.
  284. * returns dmod count.
  285. */
  286. static int
  287. dirck(Extdentry *ed, Off a)
  288. {
  289. int k, dmod = 0;
  290. if(ed->d->mode & DDIR) {
  291. dmod += touch(a);
  292. for(k=0; k<DIRPERBUF; k++) {
  293. Dentry *nd = maked(a, k, ed->qpath);
  294. if(nd == nil)
  295. break;
  296. if(fsck(nd)) {
  297. modd(a, k, nd);
  298. dmod++;
  299. }
  300. chkfree(nd);
  301. depth--;
  302. name[ed->ns] = 0;
  303. }
  304. } else if(flags & Crdall)
  305. xread(a, ed->qpath);
  306. return dmod;
  307. }
  308. /*
  309. * touch a, check a's tag for Tind1, Tind2, etc.
  310. * if the tag is right, validate each block number in the indirect block,
  311. * and check each block (mostly in case we are reading a huge directory).
  312. */
  313. static int
  314. indirck(Extdentry *ed, Off a, int tag)
  315. {
  316. int i, dmod = 0;
  317. Iobuf *p1;
  318. if (a == 0)
  319. return dmod;
  320. dmod = touch(a);
  321. if (p1 = xtag(a, tag, ed->qpath)) {
  322. for(i=0; i<INDPERBUF; i++) {
  323. a = blkck(&((Off *)p1->iobuf)[i], &p1->flags);
  324. if (a)
  325. /*
  326. * check each block named in this
  327. * indirect(^n) block (a).
  328. */
  329. if (tag == Tind1)
  330. dmod += dirck(ed, a);
  331. else
  332. dmod += indirck(ed, a, tag-1);
  333. }
  334. putbuf(p1);
  335. }
  336. return dmod;
  337. }
  338. static int
  339. indiraddrck(Extdentry *ed, Off *indirp, int tag)
  340. {
  341. int dmod;
  342. Off a;
  343. dmod = daddrck(indirp, &a);
  344. return dmod + indirck(ed, a, tag);
  345. }
  346. /* if result is true, *d was modified */
  347. static int
  348. fsck(Dentry *d)
  349. {
  350. int i, dmod;
  351. Extdentry edent;
  352. depth++;
  353. if(depth >= maxdepth)
  354. maxdepth = depth;
  355. if (lowstack == nil)
  356. startstack = lowstack = (uint8_t *)&edent;
  357. /* more precise check, assumes downward-growing stack */
  358. if ((uint8_t *)&edent < lowstack)
  359. lowstack = (uint8_t *)&edent;
  360. /* check that entry is allocated */
  361. if(!(d->mode & DALLOC))
  362. return 0;
  363. nfiles++;
  364. /* we stash qpath & ns in an Extdentry for eventual use by dirck() */
  365. memset(&edent, 0, sizeof edent);
  366. edent.d = d;
  367. /* check name */
  368. edent.ns = strlen(name);
  369. i = strlen(d->name);
  370. if(i >= NAMELEN) {
  371. d->name[NAMELEN-1] = 0;
  372. print("%s->name (%s) not terminated\n", name, d->name);
  373. return 0;
  374. }
  375. edent.ns += i;
  376. if(edent.ns >= sizname) {
  377. print("%s->name (%s) name too large\n", name, d->name);
  378. return 0;
  379. }
  380. strcat(name, d->name);
  381. if(d->mode & DDIR) {
  382. if(edent.ns > 1) {
  383. strcat(name, "/");
  384. edent.ns++;
  385. }
  386. if(flags & Cpdir) {
  387. print("%s\n", name);
  388. prflush();
  389. }
  390. } else if(flags & Cpfile) {
  391. print("%s\n", name);
  392. prflush();
  393. }
  394. /* check qid */
  395. edent.qpath = d->qid.path & ~QPDIR;
  396. qmark(edent.qpath);
  397. if(edent.qpath > maxq)
  398. maxq = edent.qpath;
  399. /* check direct blocks (the common case) */
  400. dmod = 0;
  401. {
  402. Off a;
  403. for(i=0; i<NDBLOCK; i++) {
  404. dmod += daddrck(&d->dblock[i], &a);
  405. if (a)
  406. dmod += dirck(&edent, a);
  407. }
  408. }
  409. /* check indirect^n blocks, if any */
  410. for (i = 0; i < NIBLOCK; i++)
  411. dmod += indiraddrck(&edent, &d->iblocks[i], Tind1+i);
  412. return dmod;
  413. }
  414. enum { XFEN = FEPERBUF + 6 };
  415. typedef struct {
  416. int flag;
  417. int count;
  418. int next;
  419. Off addr[XFEN];
  420. } Xfree;
  421. static void
  422. xaddfree(Device *dev, Off a, Superb *sb, Iobuf *p)
  423. {
  424. Xfree *x;
  425. x = (Xfree*)p->iobuf;
  426. if(x->count < XFEN) {
  427. x->addr[x->count] = a;
  428. x->count++;
  429. return;
  430. }
  431. if(!x->flag) {
  432. memset(&sb->fbuf, 0, sizeof(sb->fbuf));
  433. sb->fbuf.free[0] = 0L;
  434. sb->fbuf.nfree = 1;
  435. sb->tfree = 0;
  436. x->flag = 1;
  437. }
  438. addfree(dev, a, sb);
  439. }
  440. static void
  441. xflush(Device *dev, Superb *sb, Iobuf *p)
  442. {
  443. int i;
  444. Xfree *x;
  445. x = (Xfree*)p->iobuf;
  446. if(!x->flag) {
  447. memset(&sb->fbuf, 0, sizeof(sb->fbuf));
  448. sb->fbuf.free[0] = 0L;
  449. sb->fbuf.nfree = 1;
  450. sb->tfree = 0;
  451. }
  452. for(i=0; i<x->count; i++)
  453. addfree(dev, x->addr[i], sb);
  454. }
  455. /*
  456. * make freelist
  457. * from existing freelist
  458. * (cw devices)
  459. */
  460. static void
  461. trfreelist(Superb *sb)
  462. {
  463. Off a, n;
  464. int i;
  465. Iobuf *p, *xp;
  466. Fbuf *fb;
  467. xp = getbuf(devnone, Cckbuf, 0);
  468. memset(xp->iobuf, 0, BUFSIZE);
  469. fb = &sb->fbuf;
  470. p = 0;
  471. for(;;) {
  472. n = fb->nfree;
  473. if(n < 0 || n > FEPERBUF)
  474. break;
  475. for(i=1; i<n; i++) {
  476. a = fb->free[i];
  477. if(a && !ftest(a))
  478. xaddfree(dev, a, sb, xp);
  479. }
  480. a = fb->free[0];
  481. if(!a)
  482. break;
  483. if(ftest(a))
  484. break;
  485. xaddfree(dev, a, sb, xp);
  486. if(p)
  487. putbuf(p);
  488. p = xtag(a, Tfree, QPNONE);
  489. if(!p)
  490. break;
  491. fb = (Fbuf*)p->iobuf;
  492. }
  493. if(p)
  494. putbuf(p);
  495. xflush(dev, sb, xp);
  496. putbuf(xp);
  497. mod++;
  498. print("%lld blocks free\n", (Wideoff)sb->tfree);
  499. }
  500. static void
  501. ckfreelist(Superb *sb)
  502. {
  503. Off a, lo, hi;
  504. int n, i;
  505. Iobuf *p;
  506. Fbuf *fb;
  507. strcpy(name, "free list");
  508. print("check %s\n", name);
  509. fb = &sb->fbuf;
  510. a = sbaddr;
  511. p = 0;
  512. lo = 0;
  513. hi = 0;
  514. for(;;) {
  515. n = fb->nfree;
  516. if(n < 0 || n > FEPERBUF) {
  517. print("check: nfree bad %lld\n", (Wideoff)a);
  518. break;
  519. }
  520. for(i=1; i<n; i++) {
  521. a = fb->free[i];
  522. if(a && !fmark(a)) {
  523. if(!lo || lo > a)
  524. lo = a;
  525. if(!hi || hi < a)
  526. hi = a;
  527. }
  528. }
  529. a = fb->free[0];
  530. if(!a)
  531. break;
  532. if(fmark(a))
  533. break;
  534. if(!lo || lo > a)
  535. lo = a;
  536. if(!hi || hi < a)
  537. hi = a;
  538. if(p)
  539. putbuf(p);
  540. p = xtag(a, Tfree, QPNONE);
  541. if(!p)
  542. break;
  543. fb = (Fbuf*)p->iobuf;
  544. }
  545. if(p)
  546. putbuf(p);
  547. if (flags & Ctrim) {
  548. fsize = hi--; /* fsize = hi + 1 */
  549. sb->fsize = fsize;
  550. mod++;
  551. print("set fsize to %lld\n", (Wideoff)fsize);
  552. }
  553. print("lo = %lld; hi = %lld\n", (Wideoff)lo, (Wideoff)hi);
  554. }
  555. /*
  556. * make freelist from scratch
  557. */
  558. static void
  559. mkfreelist(Superb *sb)
  560. {
  561. Off a;
  562. int i, b;
  563. if(ronly) {
  564. print("cant make freelist on ronly device\n");
  565. return;
  566. }
  567. strcpy(name, "free list");
  568. memset(&sb->fbuf, 0, sizeof(sb->fbuf));
  569. sb->fbuf.free[0] = 0L;
  570. sb->fbuf.nfree = 1;
  571. sb->tfree = 0;
  572. for(a=fsize-fstart-1; a >= 0; a--) {
  573. i = a/8;
  574. if(i < 0 || i >= sizabits)
  575. continue;
  576. b = 1 << (a&7);
  577. if(abits[i] & b)
  578. continue;
  579. addfree(dev, fstart+a, sb);
  580. }
  581. print("%lld blocks free\n", (Wideoff)sb->tfree);
  582. mod++;
  583. }
  584. static Dentry*
  585. maked(Off a, int s, Off qpath)
  586. {
  587. Iobuf *p;
  588. Dentry *d, *d1;
  589. p = xtag(a, Tdir, qpath);
  590. if(!p)
  591. return 0;
  592. d = getdir(p, s);
  593. d1 = chkalloc(sizeof(Dentry));
  594. memmove(d1, d, sizeof(Dentry));
  595. putbuf(p);
  596. return d1;
  597. }
  598. static void
  599. modd(Off a, int s, Dentry *d1)
  600. {
  601. Iobuf *p;
  602. Dentry *d;
  603. if(!(flags & Cbad))
  604. return;
  605. p = getbuf(dev, a, Brd);
  606. d = getdir(p, s);
  607. if(!d) {
  608. if(p)
  609. putbuf(p);
  610. return;
  611. }
  612. memmove(d, d1, sizeof(Dentry));
  613. p->flags |= Bmod;
  614. putbuf(p);
  615. }
  616. static void
  617. xread(Off a, Off qpath)
  618. {
  619. Iobuf *p;
  620. p = xtag(a, Tfile, qpath);
  621. if(p)
  622. putbuf(p);
  623. }
  624. static Iobuf*
  625. xtag(Off a, int tag, Off qpath)
  626. {
  627. Iobuf *p;
  628. if(a == 0)
  629. return 0;
  630. p = getbuf(dev, a, Brd);
  631. if(!p) {
  632. print("check: \"%s\": xtag: p null\n", name);
  633. if(flags & (Cream|Ctag)) {
  634. p = getbuf(dev, a, Bmod);
  635. if(p) {
  636. memset(p->iobuf, 0, RBUFSIZE);
  637. settag(p, tag, qpath);
  638. mod++;
  639. return p;
  640. }
  641. }
  642. return 0;
  643. }
  644. if(checktag(p, tag, qpath)) {
  645. print("check: \"%s\": xtag: checktag\n", name);
  646. if(flags & (Cream|Ctag)) {
  647. if(flags & Cream)
  648. memset(p->iobuf, 0, RBUFSIZE);
  649. settag(p, tag, qpath);
  650. mod++;
  651. return p;
  652. }
  653. return p;
  654. }
  655. return p;
  656. }
  657. static int
  658. amark(Off a)
  659. {
  660. Off i;
  661. int b;
  662. if(a < fstart || a >= fsize) {
  663. if(a == 0)
  664. return 0;
  665. print("check: \"%s\": range %lld\n",
  666. name, (Wideoff)a);
  667. nbad++;
  668. return 1;
  669. }
  670. a -= fstart;
  671. i = a/8;
  672. b = 1 << (a&7);
  673. if(abits[i] & b) {
  674. if(!ronly)
  675. if(ndup < 10)
  676. print("check: \"%s\": address dup %lld\n",
  677. name, (Wideoff)fstart+a);
  678. else if(ndup == 10)
  679. print("...");
  680. ndup++;
  681. return 1;
  682. }
  683. abits[i] |= b;
  684. nused++;
  685. return 0;
  686. }
  687. static int
  688. fmark(Off a)
  689. {
  690. Off i;
  691. int b;
  692. if(a < fstart || a >= fsize) {
  693. print("check: \"%s\": range %lld\n",
  694. name, (Wideoff)a);
  695. nbad++;
  696. return 1;
  697. }
  698. a -= fstart;
  699. i = a/8;
  700. b = 1 << (a&7);
  701. if(abits[i] & b) {
  702. print("check: \"%s\": address dup %lld\n",
  703. name, (Wideoff)fstart+a);
  704. nfdup++;
  705. return 1;
  706. }
  707. abits[i] |= b;
  708. nfree++;
  709. return 0;
  710. }
  711. static int
  712. ftest(Off a)
  713. {
  714. Off i;
  715. int b;
  716. if(a < fstart || a >= fsize)
  717. return 1;
  718. a -= fstart;
  719. i = a/8;
  720. b = 1 << (a&7);
  721. if(abits[i] & b)
  722. return 1;
  723. abits[i] |= b;
  724. return 0;
  725. }
  726. static void
  727. missing(void)
  728. {
  729. Off a, i;
  730. int b, n;
  731. n = 0;
  732. for(a=fsize-fstart-1; a>=0; a--) {
  733. i = a/8;
  734. b = 1 << (a&7);
  735. if(!(abits[i] & b)) {
  736. print("missing: %lld\n", (Wideoff)fstart+a);
  737. n++;
  738. }
  739. if(n > 10) {
  740. print(" ...\n");
  741. break;
  742. }
  743. }
  744. }
  745. static void
  746. qmark(Off qpath)
  747. {
  748. int b;
  749. Off i;
  750. i = qpath/8;
  751. b = 1 << (qpath&7);
  752. if(i < 0 || i >= sizqbits) {
  753. nqbad++;
  754. if(nqbad < 20)
  755. print("check: \"%s\": qid out of range %llux\n",
  756. name, (Wideoff)qpath);
  757. return;
  758. }
  759. if((qbits[i] & b) && !ronly) {
  760. nqbad++;
  761. if(nqbad < 20)
  762. print("check: \"%s\": qid dup %llux\n", name,
  763. (Wideoff)qpath);
  764. }
  765. qbits[i] |= b;
  766. }