📄 chk.c
字号:
#include "all.h"#include "mem.h" /* for KZERO for PADDR *//* copied from ../pc/etherif.h; should probably be in all.h */#define HOWMANY(x, y) (((x)+((y)-1))/(y))#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))/* augmented Dentry */typedef struct { Dentry *d; Off qpath; int ns;} Extdentry;static char* abits;static long sizabits;static char* qbits;static long sizqbits;static char* name;static long sizname;static Off fstart;static Off fsize;static Off nfiles;static Off maxq;static char* calloc;static Device* dev;static Off ndup;static Off nused;static Off nfdup;static Off nqbad;static Off nfree;static Off nbad;static int mod;static int flags;static int ronly;static int cwflag;static Devsize sbaddr;static Devsize oldblock;static int depth;static int maxdepth;static uchar *lowstack, *startstack;/* local prototypes */static int fsck(Dentry*);static void ckfreelist(Superb*);static void mkfreelist(Superb*);static void trfreelist(Superb*);static void xaddfree(Device*, Off, Superb*, Iobuf*);static void xflush(Device*, Superb*, Iobuf*);static Dentry* maked(Off, int, Off);static void modd(Off, int, Dentry*);static void xread(Off, Off);static int amark(Off);static int fmark(Off);static int ftest(Off);static void missing(void);static void qmark(Off);static void* malloc(ulong);static Iobuf* xtag(Off, int, Off);staticvoid*malloc(ulong n){ char *p, *q; p = (char *)ROUNDUP((ulong)calloc, BY2WD); q = p+n; if(PADDR(q) >= conf.mem) panic("check: mem size"); calloc = q; memset(p, 0, n); return p;}/* * check flags */enum{ Crdall = (1<<0), /* read all files */ Ctag = (1<<1), /* rebuild tags */ Cpfile = (1<<2), /* print files */ Cpdir = (1<<3), /* print directories */ Cfree = (1<<4), /* rebuild free list */ Csetqid = (1<<5), /* resequence qids */ Cream = (1<<6), /* clear all bad tags */ Cbad = (1<<7), /* clear all bad blocks */ Ctouch = (1<<8), /* touch old dir and indir */ Ctrim = (1<<9), /* trim fsize back to fit when checking free list */};staticstruct{ char* option; long flag;} ckoption[] ={ "rdall", Crdall, "tag", Ctag, "pfile", Cpfile, "pdir", Cpdir, "free", Cfree, "setqid", Csetqid, "ream", Cream, "bad", Cbad, "touch", Ctouch, "trim", Ctrim, 0,};voidcmd_check(int argc, char *argv[]){ long f, i; long flag; Off raddr; Filsys *fs; Iobuf *p; Superb *sb; Dentry *d; flag = 0; for(i=1; i<argc; i++) { for(f=0; ckoption[f].option; f++) if(strcmp(argv[i], ckoption[f].option) == 0) goto found; print("unknown check option %s\n", argv[i]); for(f=0; ckoption[f].option; f++) print(" %s\n", ckoption[f].option); return; found: flag |= ckoption[f].flag; } fs = cons.curfs; dev = fs->dev; ronly = (dev->type == Devro); cwflag = (dev->type == Devcw) | (dev->type == Devro); if(!ronly) wlock(&mainlock); /* check */ /* * ialloc(0, 1) doesn't actually allocate any storage, and may * return the same address each time. see iobufinit(). * check assumes that the rest of memory, from ialloc(0, 1) * up, is available to it, but does at least check in malloc(). */ calloc = (char*)ialloc(0, 1) + 100000; flags = flag; sizqbits = ((1<<22) + 7) / 8; /* botch */ qbits = malloc(sizqbits); sbaddr = superaddr(dev); raddr = getraddr(dev); p = xtag(sbaddr, Tsuper, QPSUPER); if(!p) goto out; sb = (Superb*)p->iobuf; fstart = 2; cons.noage = 1; fsize = sb->fsize; sizabits = (fsize-fstart + 7)/8; abits = malloc(sizabits); sizname = 4000; name = malloc(sizname); sizname -= NAMELEN+10; /* for safety */ mod = 0; nfree = 0; nfdup = 0; nused = 0; nbad = 0; ndup = 0; nqbad = 0; depth = 0; maxdepth = 0; if(flags & Ctouch) { /* round fsize down to start of current side */ int s; Devsize dsize; oldblock = 0; for (s = 0; dsize = wormsizeside(dev, s), dsize > 0 && oldblock + dsize < fsize; s++) oldblock += dsize; print("oldblock = %lld\n", (Wideoff)oldblock); } amark(sbaddr); if(cwflag) { amark(sb->roraddr); amark(sb->next); } print("checking filsys: %s\n", fs->name); nfiles = 0; maxq = 0; d = maked(raddr, 0, QPROOT); if(d) { amark(raddr); if(fsck(d)) modd(raddr, 0, d); depth--; calloc -= sizeof(Dentry); if(depth) print("depth not zero on return\n"); } if(flags & Cfree) { if(cwflag) trfreelist(sb); else mkfreelist(sb); } if(sb->qidgen < maxq) print("qid generator low path=%lld maxq=%lld\n", (Wideoff)sb->qidgen, (Wideoff)maxq); if(!(flags & Cfree)) ckfreelist(sb); if(mod) { sb->qidgen = maxq; print("file system was modified\n"); settag(p, Tsuper, QPNONE); } print("nfiles = %lld\n", (Wideoff)nfiles); print("fsize = %lld\n", (Wideoff)fsize); print("nused = %lld\n", (Wideoff)nused); print("ndup = %lld\n", (Wideoff)ndup); print("nfree = %lld\n", (Wideoff)nfree); print("tfree = %lld\n", (Wideoff)sb->tfree); print("nfdup = %lld\n", (Wideoff)nfdup); print("nmiss = %lld\n", (Wideoff)fsize-fstart-nused-nfree); print("nbad = %lld\n", (Wideoff)nbad); print("nqbad = %lld\n", (Wideoff)nqbad); print("maxq = %lld\n", (Wideoff)maxq); print("base stack=%ld\n", &u->stack[sizeof(u->stack)] - startstack); print("high stack=%ld of %d\n", &u->stack[sizeof(u->stack)] - lowstack, MAXSTACK); /* high-water mark of stack usage */ print("deepest recursion=%d\n", maxdepth-1); /* one-origin */ if(!cwflag) missing();out: cons.noage = 0; putbuf(p); if(!ronly) wunlock(&mainlock);}/* * if *blkp is already allocated and Cbad is set, zero it. * returns *blkp if it's free, else 0. */static Offblkck(Off *blkp, int *flgp){ Off a = *blkp; if(amark(a)) { if(flags & Cbad) { *blkp = 0; *flgp |= Bmod; } a = 0; } return a;}/* * if a block address within a Dentry, *blkp, is already allocated * and Cbad is set, zero it. * stores 0 into *resp if already allocated, else stores *blkp. * returns dmod count. */static intdaddrck(Off *blkp, Off *resp){ int dmod = 0; if(amark(*blkp)) { if(flags & Cbad) { *blkp = 0; dmod++; } *resp = 0; } else *resp = *blkp; return dmod;}/* * under Ctouch, read block `a' if it's in range. * returns dmod count. */static inttouch(Off a){ if((flags&Ctouch) && a < oldblock) { Iobuf *pd = getbuf(dev, a, Bread|Bmod); if(pd) putbuf(pd); return 1; } return 0;}/* * if d is a directory, touch it and check all its entries in block a. * if not, under Crdall, read a. * returns dmod count. */static intdirck(Extdentry *ed, Off a){ int k, dmod = 0; if(ed->d->mode & DDIR) { dmod += touch(a); for(k=0; k<DIRPERBUF; k++) { Dentry *nd = maked(a, k, ed->qpath); if(nd == nil) break; if(fsck(nd)) { modd(a, k, nd); dmod++; } depth--; calloc -= sizeof(Dentry); name[ed->ns] = 0; } } else if(flags & Crdall) xread(a, ed->qpath); return dmod;}/* * touch a, check a's tag for Tind1, Tind2, etc. * if the tag is right, validate each block number in the indirect block, * and check each block (mostly in case we are reading a huge directory). */static intindirck(Extdentry *ed, Off a, int tag){ int i, dmod = 0; Iobuf *p1; if (a == 0) return dmod; dmod = touch(a); if (p1 = xtag(a, tag, ed->qpath)) { for(i=0; i<INDPERBUF; i++) { a = blkck(&((Off *)p1->iobuf)[i], &p1->flags); if (a) /* * check each block named in this * indirect(^n) block (a). */ if (tag == Tind1) dmod += dirck(ed, a); else dmod += indirck(ed, a, tag-1); } putbuf(p1); } return dmod;}static intindiraddrck(Extdentry *ed, Off *indirp, int tag){ int dmod; Off a; dmod = daddrck(indirp, &a); return dmod + indirck(ed, a, tag);}/* if result is true, *d was modified */staticintfsck(Dentry *d){ int i, dmod; Extdentry edent; depth++; if(depth >= maxdepth) { maxdepth = depth; /* * On a 386 each recursion costs ~100 bytes (more for * directories with indirect blocks). Base stack usage * is about ~320 bytes, leaving room for ~156 recursions * (assuming a 16000-byte stack). Typical checks use * around 12 recursions. * Alternatives here might be to give the check process * a much bigger stack or rewrite it without recursion, * but it hardly seems worth expending effort on. */ if(maxdepth >= MAXSTACK/(100+10)) { print("check: max depth exceeded: %s\n", name); return 0; } } if (lowstack == nil) startstack = lowstack = (uchar *)&edent; /* more precise check, assumes downward-growing stack */ if ((uchar *)&edent < lowstack) lowstack = (uchar *)&edent; if ((uchar *)&edent < &u->stack[500]) { print("check: stack nearly full: %s\n", name); return 0; } /* check that entry is allocated */ if(!(d->mode & DALLOC)) return 0; nfiles++; /* we stash qpath & ns in an Extdentry for eventual use by dirck() */ memset(&edent, 0, sizeof edent); edent.d = d; /* check name */ edent.ns = strlen(name); i = strlen(d->name); if(i >= NAMELEN) { d->name[NAMELEN-1] = 0; print("%s->name (%s) not terminated\n", name, d->name); return 0; } edent.ns += i; if(edent.ns >= sizname) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -