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