/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "all.h" /* 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 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 amark(Off);static void* chkalloc(ulong);static void ckfreelist(Superb*);static int fmark(Off);static int fsck(Dentry*);static int ftest(Off);static Dentry* maked(Off, int, Off);static void missing(void);static void mkfreelist(Superb*);static void modd(Off, int, Dentry*);static void qmark(Off);static void trfreelist(Superb*);static void xaddfree(Device*, Off, Superb*, Iobuf*);static void xflush(Device*, Superb*, Iobuf*);static void xread(Off, Off);static Iobuf* xtag(Off, int, Off); static void *chkalloc(ulong n){ char *p = mallocz(n, 1); if (p == nil) panic("chkalloc: out of memory"); return p;} voidchkfree(void *p){ free(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 */}; static struct { 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, 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("\t%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 */ flags = flag; name = abits = qbits = nil; /* in case of goto */ sbaddr = superaddr(dev); raddr = getraddr(dev); p = xtag(sbaddr, Tsuper, QPSUPER); if(!p) goto out; sb = (Superb*)p->iobuf; fstart = 2; cons.noage = 1; /* 200 is slop since qidgen is likely to be a little bit low */ sizqbits = (sb->qidgen+200 + 7) / 8; qbits = chkalloc(sizqbits); fsize = sb->fsize; sizabits = (fsize-fstart + 7)/8; abits = chkalloc(sizabits); sizname = 4000; name = chkalloc(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); chkfree(d); depth--; 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=%llud\n", (vlong)startstack); /* high-water mark of stack usage */ print("high stack=%llud\n", (vlong)lowstack); print("deepest recursion=%d\n", maxdepth-1); /* one-origin */ if(!cwflag) missing(); out: cons.noage = 0; putbuf(p); chkfree(name); chkfree(abits); chkfree(qbits); name = abits = qbits = nil; 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, Brd|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++; } chkfree(nd); depth--; 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 */static intfsck(Dentry *d){ int i, dmod; Extdentry edent; depth++; if(depth >= maxdepth) maxdepth = depth; if (lowstack == nil) startstack = lowstack = (uchar *)&edent; /* more precise check, assumes downward-growing stack */ if ((uchar *)&edent < lowstack) lowstack = (uchar *)&edent; /* 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) { print("%s->name (%s) name too large\n", name, d->name); return 0; } strcat(name, d->name); if(d->mode & DDIR) { if(edent.ns > 1) { strcat(name, "/"); edent.ns++; } if(flags & Cpdir) { print("%s\n", name); prflush(); } } else if(flags & Cpfile) { print("%s\n", name); prflush(); } /* check qid */ edent.qpath = d->qid.path & ~QPDIR; qmark(edent.qpath); if(edent.qpath > maxq) maxq = edent.qpath; /* check direct blocks (the common case) */ dmod = 0; { Off a; for(i=0; i<NDBLOCK; i++) { dmod += daddrck(&d->dblock[i], &a); if (a) dmod += dirck(&edent, a); } } /* check indirect^n blocks, if any */ for (i = 0; i < NIBLOCK; i++) dmod += indiraddrck(&edent, &d->iblocks[i], Tind1+i); return dmod;} enum { XFEN = FEPERBUF + 6 }; typedef struct { int flag; int count; int next; Off addr[XFEN];} Xfree; static voidxaddfree(Device *dev, Off a, Superb *sb, Iobuf *p){ Xfree *x; x = (Xfree*)p->iobuf; if(x->count < XFEN) { x->addr[x->count] = a; x->count++; return; } if(!x->flag) { memset(&sb->fbuf, 0, sizeof(sb->fbuf)); sb->fbuf.free[0] = 0L; sb->fbuf.nfree = 1; sb->tfree = 0; x->flag = 1; } addfree(dev, a, sb);} static voidxflush(Device *dev, Superb *sb, Iobuf *p){ int i; Xfree *x; Lines 1–500 of 847. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "all.h" /* 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 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 amark(Off); static void* chkalloc(ulong); static void ckfreelist(Superb*); static int fmark(Off); static int fsck(Dentry*); static int ftest(Off); static Dentry* maked(Off, int, Off); static void missing(void); static void mkfreelist(Superb*); static void modd(Off, int, Dentry*); static void qmark(Off); static void trfreelist(Superb*); static void xaddfree(Device*, Off, Superb*, Iobuf*); static void xflush(Device*, Superb*, Iobuf*); static void xread(Off, Off); static Iobuf* xtag(Off, int, Off); static void * chkalloc(ulong n) { char *p = mallocz(n, 1); if (p == nil) panic("chkalloc: out of memory"); return p; } void chkfree(void *p) { free(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 */ }; static struct { 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, }; void cmd_check(int argc, char *argv[]) { long f, i, 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("\t%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 */ flags = flag; name = abits = qbits = nil; /* in case of goto */ sbaddr = superaddr(dev); raddr = getraddr(dev); p = xtag(sbaddr, Tsuper, QPSUPER); if(!p) goto out; sb = (Superb*)p->iobuf; fstart = 2; cons.noage = 1; /* 200 is slop since qidgen is likely to be a little bit low */ sizqbits = (sb->qidgen+200 + 7) / 8; qbits = chkalloc(sizqbits); fsize = sb->fsize; sizabits = (fsize-fstart + 7)/8; abits = chkalloc(sizabits); sizname = 4000; name = chkalloc(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); chkfree(d); depth--; 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=%llud\n", (vlong)startstack); /* high-water mark of stack usage */ print("high stack=%llud\n", (vlong)lowstack); print("deepest recursion=%d\n", maxdepth-1); /* one-origin */ if(!cwflag) missing(); out: cons.noage = 0; putbuf(p); chkfree(name); chkfree(abits); chkfree(qbits); name = abits = qbits = nil; if(!ronly) wunlock(&mainlock); } /* * if *blkp is already allocated and Cbad is set, zero it. * returns *blkp if it's free, else 0. */ static Off blkck(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 int daddrck(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 int touch(Off a) { if((flags&Ctouch) && a < oldblock) { Iobuf *pd = getbuf(dev, a, Brd|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 int dirck(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++; } chkfree(nd); depth--; 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 int indirck(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 int indiraddrck(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 */ static int fsck(Dentry *d) { int i, dmod; Extdentry edent; depth++; if(depth >= maxdepth) maxdepth = depth; if (lowstack == nil) startstack = lowstack = (uchar *)&edent; /* more precise check, assumes downward-growing stack */ if ((uchar *)&edent < lowstack) lowstack = (uchar *)&edent; /* 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) { print("%s->name (%s) name too large\n", name, d->name); return 0; } strcat(name, d->name); if(d->mode & DDIR) { if(edent.ns > 1) { strcat(name, "/"); edent.ns++; } if(flags & Cpdir) { print("%s\n", name); prflush(); } } else if(flags & Cpfile) { print("%s\n", name); prflush(); } /* check qid */ edent.qpath = d->qid.path & ~QPDIR; qmark(edent.qpath); if(edent.qpath > maxq) maxq = edent.qpath; /* check direct blocks (the common case) */ dmod = 0; { Off a; for(i=0; i<NDBLOCK; i++) { dmod += daddrck(&d->dblock[i], &a); if (a) dmod += dirck(&edent, a); } } /* check indirect^n blocks, if any */ for (i = 0; i < NIBLOCK; i++) dmod += indiraddrck(&edent, &d->iblocks[i], Tind1+i); return dmod; } enum { XFEN = FEPERBUF + 6 }; typedef struct { int flag; int count; int next; Off addr[XFEN]; } Xfree; static void xaddfree(Device *dev, Off a, Superb *sb, Iobuf *p) { Xfree *x; x = (Xfree*)p->iobuf; if(x->count < XFEN) { x->addr[x->count] = a; x->count++; return; } if(!x->flag) { memset(&sb->fbuf, 0, sizeof(sb->fbuf)); sb->fbuf.free[0] = 0L; sb->fbuf.nfree = 1; sb->tfree = 0; x->flag = 1; } addfree(dev, a, sb); } static void xflush(Device *dev, Superb *sb, Iobuf *p) { int i; Xfree *x;