chk.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. #include "all.h"
  2. #define DSIZE 546000
  3. #define MAXDEPTH 100
  4. static char* abits;
  5. static long sizabits;
  6. static char* qbits;
  7. static long sizqbits;
  8. static char* name;
  9. static long sizname;
  10. static long fstart;
  11. static long fsize;
  12. static long nfiles;
  13. static long maxq;
  14. static char* fence;
  15. static char* fencebase;
  16. static Device dev;
  17. static long ndup;
  18. static long nused;
  19. static long nfdup;
  20. static long nqbad;
  21. static long nfree;
  22. static long nbad;
  23. static int mod;
  24. static int flags;
  25. static int ronly;
  26. static int cwflag;
  27. static long sbaddr;
  28. static long oldblock;
  29. static int depth;
  30. static int maxdepth;
  31. /* local prototypes */
  32. static int fsck(Dentry*);
  33. static void ckfreelist(Superb*);
  34. static void mkfreelist(Superb*);
  35. static Dentry* maked(long, int, long);
  36. static void modd(long, int, Dentry*);
  37. static void xread(long, long);
  38. static int amark(long);
  39. static int fmark(long);
  40. static void missing(void);
  41. static void qmark(long);
  42. static void* zalloc(ulong);
  43. static void* dalloc(ulong);
  44. static Iobuf* xtag(long, int, long);
  45. static
  46. void*
  47. zalloc(ulong n)
  48. {
  49. char *p;
  50. p = malloc(n);
  51. if(p == 0)
  52. panic("zalloc: out of memory\n");
  53. memset(p, '\0', n);
  54. return p;
  55. }
  56. static
  57. void*
  58. dalloc(ulong n)
  59. {
  60. char *p;
  61. if(fencebase == 0)
  62. fence = fencebase = zalloc(MAXDEPTH*sizeof(Dentry));
  63. p = fence;
  64. fence += n;
  65. if(fence > fencebase+MAXDEPTH*sizeof(Dentry))
  66. panic("dalloc too much memory\n");
  67. return p;
  68. }
  69. void
  70. check(Filsys *fs, long flag)
  71. {
  72. Iobuf *p;
  73. Superb *sb;
  74. Dentry *d;
  75. long raddr;
  76. long nqid;
  77. wlock(&mainlock);
  78. dev = fs->dev;
  79. flags = flag;
  80. fence = fencebase;
  81. sizname = 4000;
  82. name = zalloc(sizname);
  83. sizname -= NAMELEN+10; /* for safety */
  84. sbaddr = superaddr(dev);
  85. raddr = getraddr(dev);
  86. p = xtag(sbaddr, Tsuper, QPSUPER);
  87. if(!p){
  88. cprint("bad superblock\n");
  89. goto out;
  90. }
  91. sb = (Superb*)p->iobuf;
  92. fstart = 1;
  93. fsize = sb->fsize;
  94. sizabits = (fsize-fstart + 7)/8;
  95. abits = zalloc(sizabits);
  96. nqid = sb->qidgen+100; /* not as much of a botch */
  97. if(nqid > 1024*1024*8)
  98. nqid = 1024*1024*8;
  99. if(nqid < 64*1024)
  100. nqid = 64*1024;
  101. sizqbits = (nqid+7)/8;
  102. qbits = zalloc(sizqbits);
  103. mod = 0;
  104. nfree = 0;
  105. nfdup = 0;
  106. nused = 0;
  107. nbad = 0;
  108. ndup = 0;
  109. nqbad = 0;
  110. depth = 0;
  111. maxdepth = 0;
  112. if(flags & Ctouch) {
  113. oldblock = fsize/DSIZE;
  114. oldblock *= DSIZE;
  115. if(oldblock < 0)
  116. oldblock = 0;
  117. cprint("oldblock = %ld\n", oldblock);
  118. }
  119. if(amark(sbaddr))
  120. {}
  121. if(cwflag) {
  122. if(amark(sb->roraddr))
  123. {}
  124. if(amark(sb->next))
  125. {}
  126. }
  127. if(!(flags & Cquiet))
  128. cprint("checking file system: %s\n", fs->name);
  129. nfiles = 0;
  130. maxq = 0;
  131. d = maked(raddr, 0, QPROOT);
  132. if(d) {
  133. if(amark(raddr))
  134. {}
  135. if(fsck(d))
  136. modd(raddr, 0, d);
  137. depth--;
  138. fence -= sizeof(Dentry);
  139. if(depth)
  140. cprint("depth not zero on return\n");
  141. }
  142. if(flags & Cfree) {
  143. mkfreelist(sb);
  144. sb->qidgen = maxq;
  145. settag(p, Tsuper, QPNONE);
  146. }
  147. if(sb->qidgen < maxq)
  148. cprint("qid generator low path=%ld maxq=%ld\n",
  149. sb->qidgen, maxq);
  150. if(!(flags & Cfree))
  151. ckfreelist(sb);
  152. if(mod) {
  153. cprint("file system was modified\n");
  154. settag(p, Tsuper, QPNONE);
  155. }
  156. if(!(flags & Cquiet)){
  157. cprint("%8ld files\n", nfiles);
  158. cprint("%8ld blocks in the file system\n", fsize-fstart);
  159. cprint("%8ld used blocks\n", nused);
  160. cprint("%8ld free blocks\n", sb->tfree);
  161. }
  162. if(!(flags & Cfree)){
  163. if(nfree != sb->tfree)
  164. cprint("%8ld free blocks found\n", nfree);
  165. if(nfdup)
  166. cprint("%8ld blocks duplicated in the free list\n", nfdup);
  167. if(fsize-fstart-nused-nfree)
  168. cprint("%8ld missing blocks\n", fsize-fstart-nused-nfree);
  169. }
  170. if(ndup)
  171. cprint("%8ld address duplications\n", ndup);
  172. if(nbad)
  173. cprint("%8ld bad block addresses\n", nbad);
  174. if(nqbad)
  175. cprint("%8ld bad qids\n", nqbad);
  176. if(!(flags & Cquiet))
  177. cprint("%8ld maximum qid path\n", maxq);
  178. missing();
  179. out:
  180. if(p)
  181. putbuf(p);
  182. free(abits);
  183. free(name);
  184. free(qbits);
  185. wunlock(&mainlock);
  186. }
  187. static
  188. int
  189. touch(long a)
  190. {
  191. Iobuf *p;
  192. if((flags&Ctouch) && a && a < oldblock){
  193. p = getbuf(dev, a, Bread|Bmod);
  194. if(p)
  195. putbuf(p);
  196. return 1;
  197. }
  198. return 0;
  199. }
  200. static
  201. int
  202. checkdir(long a, long qpath)
  203. {
  204. Dentry *nd;
  205. int i, ns, dmod;
  206. ns = strlen(name);
  207. dmod = touch(a);
  208. for(i=0; i<DIRPERBUF; i++) {
  209. nd = maked(a, i, qpath);
  210. if(!nd)
  211. break;
  212. if(fsck(nd)) {
  213. modd(a, i, nd);
  214. dmod++;
  215. }
  216. depth--;
  217. fence -= sizeof(Dentry);
  218. name[ns] = 0;
  219. }
  220. name[ns] = 0;
  221. return dmod;
  222. }
  223. static
  224. int
  225. checkindir(long a, Dentry *d, long qpath)
  226. {
  227. Iobuf *p;
  228. int i, dmod;
  229. dmod = touch(a);
  230. p = xtag(a, Tind1, qpath);
  231. if(!p)
  232. return dmod;
  233. for(i=0; i<INDPERBUF; i++) {
  234. a = ((long*)p->iobuf)[i];
  235. if(!a)
  236. continue;
  237. if(amark(a)) {
  238. if(flags & Cbad) {
  239. ((long*)p->iobuf)[i] = 0;
  240. p->flags |= Bmod;
  241. }
  242. continue;
  243. }
  244. if(d->mode & DDIR)
  245. dmod += checkdir(a, qpath);
  246. else if(flags & Crdall)
  247. xread(a, qpath);
  248. }
  249. putbuf(p);
  250. return dmod;
  251. }
  252. static
  253. int
  254. fsck(Dentry *d)
  255. {
  256. char *s;
  257. Rune r;
  258. Iobuf *p;
  259. int l, i, ns, dmod;
  260. long a, qpath;
  261. depth++;
  262. if(depth >= maxdepth){
  263. maxdepth = depth;
  264. if(maxdepth >= MAXDEPTH){
  265. cprint("max depth exceeded: %s\n", name);
  266. return 0;
  267. }
  268. }
  269. dmod = 0;
  270. if(!(d->mode & DALLOC))
  271. return 0;
  272. nfiles++;
  273. ns = strlen(name);
  274. i = strlen(d->name);
  275. if(i >= NAMELEN){
  276. d->name[NAMELEN-1] = 0;
  277. cprint("%s->name (%s) not terminated\n", name, d->name);
  278. return 0;
  279. }
  280. ns += i;
  281. if(ns >= sizname){
  282. cprint("%s->name (%s) name too large\n", name, d->name);
  283. return 0;
  284. }
  285. for (s = d->name; *s; s += l){
  286. l = chartorune(&r, s);
  287. if (r == Runeerror)
  288. for (i = 0; i < l; i++){
  289. s[i] = '_';
  290. cprint("%s->name (%s) bad UTF\n", name, d->name);
  291. dmod++;
  292. }
  293. }
  294. strcat(name, d->name);
  295. if(d->mode & DDIR){
  296. if(ns > 1)
  297. strcat(name, "/");
  298. if(flags & Cpdir)
  299. cprint("%s\n", name);
  300. } else
  301. if(flags & Cpfile)
  302. cprint("%s\n", name);
  303. qpath = d->qid.path & ~QPDIR;
  304. qmark(qpath);
  305. if(qpath > maxq)
  306. maxq = qpath;
  307. for(i=0; i<NDBLOCK; i++) {
  308. a = d->dblock[i];
  309. if(!a)
  310. continue;
  311. if(amark(a)) {
  312. d->dblock[i] = 0;
  313. dmod++;
  314. continue;
  315. }
  316. if(d->mode & DDIR)
  317. dmod += checkdir(a, qpath);
  318. else if(flags & Crdall)
  319. xread(a, qpath);
  320. }
  321. a = d->iblock;
  322. if(a && amark(a)) {
  323. d->iblock = 0;
  324. dmod++;
  325. }
  326. else if(a)
  327. dmod += checkindir(a, d, qpath);
  328. a = d->diblock;
  329. if(a && amark(a)) {
  330. d->diblock = 0;
  331. return dmod + 1;
  332. }
  333. dmod += touch(a);
  334. if(p = xtag(a, Tind2, qpath)){
  335. for(i=0; i<INDPERBUF; i++){
  336. a = ((long*)p->iobuf)[i];
  337. if(!a)
  338. continue;
  339. if(amark(a)) {
  340. if(flags & Cbad) {
  341. ((long*)p->iobuf)[i] = 0;
  342. p->flags |= Bmod;
  343. }
  344. continue;
  345. }
  346. dmod += checkindir(a, d, qpath);
  347. }
  348. putbuf(p);
  349. }
  350. return dmod;
  351. }
  352. static
  353. void
  354. ckfreelist(Superb *sb)
  355. {
  356. long a, lo, hi;
  357. int n, i;
  358. Iobuf *p;
  359. Fbuf *fb;
  360. strcpy(name, "free list");
  361. cprint("check %s\n", name);
  362. fb = &sb->fbuf;
  363. a = sbaddr;
  364. p = 0;
  365. lo = 0;
  366. hi = 0;
  367. for(;;) {
  368. n = fb->nfree;
  369. if(n < 0 || n > FEPERBUF) {
  370. cprint("check: nfree bad %ld\n", a);
  371. break;
  372. }
  373. for(i=1; i<n; i++) {
  374. a = fb->free[i];
  375. if(a && !fmark(a)) {
  376. if(!lo || lo > a)
  377. lo = a;
  378. if(!hi || hi < a)
  379. hi = a;
  380. }
  381. }
  382. a = fb->free[0];
  383. if(!a)
  384. break;
  385. if(fmark(a))
  386. break;
  387. if(!lo || lo > a)
  388. lo = a;
  389. if(!hi || hi < a)
  390. hi = a;
  391. if(p)
  392. putbuf(p);
  393. p = xtag(a, Tfree, QPNONE);
  394. if(!p)
  395. break;
  396. fb = (Fbuf*)p->iobuf;
  397. }
  398. if(p)
  399. putbuf(p);
  400. cprint("lo = %ld; hi = %ld\n", lo, hi);
  401. }
  402. /*
  403. * make freelist from scratch
  404. */
  405. static
  406. void
  407. mkfreelist(Superb *sb)
  408. {
  409. long a;
  410. int i, b;
  411. strcpy(name, "free list");
  412. memset(&sb->fbuf, 0, sizeof(sb->fbuf));
  413. sb->fbuf.nfree = 1;
  414. sb->tfree = 0;
  415. for(a=fsize-fstart-1; a >= 0; a--) {
  416. i = a/8;
  417. if(i < 0 || i >= sizabits)
  418. continue;
  419. b = 1 << (a&7);
  420. if(abits[i] & b)
  421. continue;
  422. addfree(dev, fstart+a, sb);
  423. abits[i] |= b;
  424. }
  425. }
  426. static
  427. Dentry*
  428. maked(long a, int s, long qpath)
  429. {
  430. Iobuf *p;
  431. Dentry *d, *d1;
  432. p = xtag(a, Tdir, qpath);
  433. if(!p)
  434. return 0;
  435. d = getdir(p, s);
  436. d1 = dalloc(sizeof(Dentry));
  437. memmove(d1, d, sizeof(Dentry));
  438. putbuf(p);
  439. return d1;
  440. }
  441. static
  442. void
  443. modd(long a, int s, Dentry *d1)
  444. {
  445. Iobuf *p;
  446. Dentry *d;
  447. if(!(flags & Cbad))
  448. return;
  449. p = getbuf(dev, a, Bread);
  450. d = getdir(p, s);
  451. if(!d) {
  452. if(p)
  453. putbuf(p);
  454. return;
  455. }
  456. memmove(d, d1, sizeof(Dentry));
  457. p->flags |= Bmod;
  458. putbuf(p);
  459. }
  460. static
  461. void
  462. xread(long a, long qpath)
  463. {
  464. Iobuf *p;
  465. p = xtag(a, Tfile, qpath);
  466. if(p)
  467. putbuf(p);
  468. }
  469. static
  470. Iobuf*
  471. xtag(long a, int tag, long qpath)
  472. {
  473. Iobuf *p;
  474. if(a == 0)
  475. return 0;
  476. p = getbuf(dev, a, Bread);
  477. if(!p) {
  478. cprint("check: \"%s\": xtag: p null\n", name);
  479. if(flags & (Cream|Ctag)) {
  480. p = getbuf(dev, a, Bmod);
  481. if(p) {
  482. memset(p->iobuf, 0, RBUFSIZE);
  483. settag(p, tag, qpath);
  484. mod++;
  485. return p;
  486. }
  487. }
  488. return 0;
  489. }
  490. if(checktag(p, tag, qpath)) {
  491. cprint("check: \"%s\": xtag: checktag\n", name);
  492. if(flags & Cream)
  493. memset(p->iobuf, 0, RBUFSIZE);
  494. if(flags & (Cream|Ctag)) {
  495. settag(p, tag, qpath);
  496. mod++;
  497. }
  498. return p;
  499. }
  500. return p;
  501. }
  502. static
  503. int
  504. amark(long a)
  505. {
  506. long i;
  507. int b;
  508. if(a < fstart || a >= fsize) {
  509. cprint("check: \"%s\": range %ld\n",
  510. name, a);
  511. nbad++;
  512. return 1;
  513. }
  514. a -= fstart;
  515. i = a/8;
  516. b = 1 << (a&7);
  517. if(abits[i] & b) {
  518. if(!ronly) {
  519. if(ndup < 10)
  520. cprint("check: \"%s\": address dup %ld\n",
  521. name, fstart+a);
  522. else
  523. if(ndup == 10)
  524. cprint("...");
  525. }
  526. ndup++;
  527. return 0; /* really?? */
  528. }
  529. abits[i] |= b;
  530. nused++;
  531. return 0;
  532. }
  533. static
  534. int
  535. fmark(long a)
  536. {
  537. long i;
  538. int b;
  539. if(a < fstart || a >= fsize) {
  540. cprint("check: \"%s\": range %ld\n",
  541. name, a);
  542. nbad++;
  543. return 1;
  544. }
  545. a -= fstart;
  546. i = a/8;
  547. b = 1 << (a&7);
  548. if(abits[i] & b) {
  549. cprint("check: \"%s\": address dup %ld\n",
  550. name, fstart+a);
  551. nfdup++;
  552. return 1;
  553. }
  554. abits[i] |= b;
  555. nfree++;
  556. return 0;
  557. }
  558. static
  559. void
  560. missing(void)
  561. {
  562. long a, i;
  563. int b, n;
  564. n = 0;
  565. for(a=fsize-fstart-1; a>=0; a--) {
  566. i = a/8;
  567. b = 1 << (a&7);
  568. if(!(abits[i] & b)) {
  569. cprint("missing: %ld\n", fstart+a);
  570. n++;
  571. }
  572. if(n > 10) {
  573. cprint(" ...\n");
  574. break;
  575. }
  576. }
  577. }
  578. static
  579. void
  580. qmark(long qpath)
  581. {
  582. int i, b;
  583. i = qpath/8;
  584. b = 1 << (qpath&7);
  585. if(i < 0 || i >= sizqbits) {
  586. nqbad++;
  587. if(nqbad < 20)
  588. cprint("check: \"%s\": qid out of range %lux\n",
  589. name, qpath);
  590. return;
  591. }
  592. if((qbits[i] & b) && !ronly) {
  593. nqbad++;
  594. if(nqbad < 20)
  595. cprint("check: \"%s\": qid dup %lux\n",
  596. name, qpath);
  597. }
  598. qbits[i] |= b;
  599. }