847 lines · 14.6 KB · C
RawDownload
/*  * 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t