699 lines · 11.0 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" Lock wpathlock; struct {	Lock	flock;	File*	ffree;		/* free file structures */	Wpath*	wfree;} suballoc; enum{	Finc=	128,	/* allocation chunksize for files */	Fmax=	10000,	/* maximum file structures to be allocated */		Winc=	8*128,	/* allocation chunksize for wpath */	Wmax=	8*10000,	/* maximum wpath structures to be allocated */};  Filsys*fsstr(char *p){	Filsys *fs; 	for(fs=filesys; fs->name; fs++)		if(strcmp(fs->name, p) == 0)			return fs;	return 0;} voidfileinit(Chan *cp){	File *f;	Tlock *t; loop:	lock(&cp->flock);	f = cp->flist;	if(!f) {		unlock(&cp->flock);		return;	}	cp->flist = f->next;	unlock(&cp->flock); 	qlock(f);	if(t = f->tlock) {		t->time = 0;		f->tlock = 0;	}	if(f->open & FREMOV)		doremove(f, 0);	freewp(f->wpath);	f->open = 0;	f->cp = 0;	qunlock(f); 	goto loop;} /* * returns a locked file structure */File*filep(Chan *cp, int fid, int flag){	File *f, *prev; 	if(fid == NOF)		return 0; loop:	lock(&cp->flock);	for(prev=0,f=cp->flist; f; prev=f,f=f->next) {		if(f->fid != fid)			continue;		if(prev) {			prev->next = f->next;			f->next = cp->flist;			cp->flist = f;		}		goto out;	}	if(flag) {		f = newfp(cp);		if(f) {			f->fid = fid;			goto out;		}	}else print("cannot find %p.%d (list=%p)\n", cp, fid, cp->flist);	unlock(&cp->flock);	return 0; out:	unlock(&cp->flock);	qlock(f);	if(f->fid != fid) {		qunlock(f);		goto loop;	}	return f;} voidsublockinit(void){	lock(&suballoc.flock);	lock(&wpathlock);	conf.nfile = 0;	conf.nwpath = 0;	unlock(&suballoc.flock);	unlock(&wpathlock);}	 /* * always called with cp->flock locked */File*newfp(Chan *cp){	File *f, *e; retry:	lock(&suballoc.flock);	f = suballoc.ffree;	if(f != nil){		suballoc.ffree = f->list;		unlock(&suballoc.flock);		f->list = 0;		f->cp = cp;		f->next = cp->flist;		f->wpath = 0;		f->tlock = 0;		f->dslot = 0;		f->doffset = 0;		f->uid = 0;		f->cuid = 0;		cp->flist = f;		return f;	}	unlock(&suballoc.flock); 	if(conf.nfile > Fmax){		print("%d: out of files\n", cp->chan);		return 0;	} 	/*	 *  create a few new files	 */	f = malloc(Finc*sizeof(*f));	memset(f, 0, Finc*sizeof(*f));	lock(&suballoc.flock);	for(e = f+Finc; f < e; f++){		qlock(f);		qunlock(f);		f->list = suballoc.ffree;		suballoc.ffree = f;	}	conf.nfile += Finc;	unlock(&suballoc.flock);	goto retry;} voidfreefp(File *fp){	Chan *cp;	File *f, *prev; 	if(!fp || !(cp = fp->cp))		return;	authfree(fp);	lock(&cp->flock);	for(prev=0,f=cp->flist; f; prev=f,f=f->next) {		if(f != fp)			continue;		if(prev)			prev->next = f->next;		else			cp->flist = f->next;		f->cp = 0;		lock(&suballoc.flock);		f->list = suballoc.ffree;		suballoc.ffree = f;		unlock(&suballoc.flock);		break;	}	unlock(&cp->flock);} Wpath*newwp(void){	Wpath *w, *e; retry:	lock(&wpathlock);	w = suballoc.wfree;	if(w != nil){		suballoc.wfree = w->list;		unlock(&wpathlock);		memset(w, 0, sizeof(*w));		w->refs = 1;		w->up = 0;		return w;	}	unlock(&wpathlock); 	if(conf.nwpath > Wmax){		print("out of wpaths\n");		return 0;	} 	/*	 *  create a few new wpaths	 */	w = malloc(Winc*sizeof(*w));	memset(w, 0, Winc*sizeof(*w));	lock(&wpathlock);	for(e = w+Winc; w < e; w++){		w->list = suballoc.wfree;		suballoc.wfree = w;	}	conf.nwpath += Winc;	unlock(&wpathlock);	goto retry;} /* *  increment the references for the whole path */Wpath*getwp(Wpath *w){	Wpath *nw; 	lock(&wpathlock);	for(nw = w; nw; nw=nw->up)		nw->refs++;	unlock(&wpathlock);	return w;} /* *  decrement the reference for each element of the path */voidfreewp(Wpath *w){	lock(&wpathlock);	for(; w; w=w->up){		w->refs--;		if(w->refs == 0){			w->list = suballoc.wfree;			suballoc.wfree = w;		}	}	unlock(&wpathlock);} /* *  decrement the reference for just this element */voidputwp(Wpath *w){	lock(&wpathlock);	w->refs--;	if(w->refs == 0){		w->list = suballoc.wfree;		suballoc.wfree = w;	}	unlock(&wpathlock);} intiaccess(File *f, Dentry *d, int m){	if(wstatallow)		return 0; 	/*	 * owner is next	 */	if(f->uid == d->uid)		if((m<<6) & d->mode)			return 0;	/*	 * group membership is hard	 */	if(ingroup(f->uid, d->gid))		if((m<<3) & d->mode)			return 0;	/*	 * other access for everyone except members of group 9999	 */	if(m & d->mode){		/* 		 *  walk directories regardless.		 *  otherwise its impossible to get		 *  from the root to noworld's directories.		 */		if((d->mode & DDIR) && (m == DEXEC))			return 0;		if(!ingroup(f->uid, 9999))			return 0;	}	return 1;} Tlock*tlocked(Iobuf *p, Dentry *d){	Tlock *t, *t1;	long qpath, tim;	Device dev; 	tim = time(0);	qpath = d->qid.path;	dev = p->dev;	t1 = 0;	for(t=tlocks+NTLOCK-1; t>=tlocks; t--) {		if(t->qpath == qpath)		if(t->time >= tim)		if(devcmp(t->dev, dev) == 0)			return 0;		/* its locked */		if(!t1 && t->time < tim)			t1 = t;			/* steal first lock */	}	if(t1) {		t1->dev = dev;		t1->qpath = qpath;		t1->time = tim + TLOCK;	}	/* botch	 * out of tlock nodes simulates	 * a locked file	 */	return t1;} Qidnewqid(Device dev){	Iobuf *p;	Superb *sb;	Qid qid; 	p = getbuf(dev, superaddr(dev), Bread|Bmod);	if(!p || checktag(p, Tsuper, QPSUPER))		panic("newqid: super block");	sb = (Superb*)p->iobuf;	sb->qidgen++;	qid.path = sb->qidgen;	qid.vers = 0;	qid.type = 0;	putbuf(p);	return qid;} /* * what are legal characters in a name? * only disallow control characters. * a) utf avoids control characters. * b) '/' may not be the separator */intcheckname(char *n){	int i, c; 	for(i=0; i<NAMELEN; i++) {		c = *n & 0xff;		if(c == 0) {			if(i == 0)				return 1;			memset(n, 0, NAMELEN-i);			return 0;		}		if(c <= 040)			return 1;		n++;	}	return 1;	/* too long */} voidbfree(Device dev, long addr, int d){	Iobuf *p;	long a;	int i; 	if(!addr)		return;	if(d > 0) {		d--;		p = getbuf(dev, addr, Bread);		if(p) {			for(i=INDPERBUF-1; i>=0; i--) {				a = ((long*)p->iobuf)[i];				bfree(dev, a, d);			}			putbuf(p);		}	}	/*	 * stop outstanding i/o	 */	p = getbuf(dev, addr, Bprobe);	if(p) {		p->flags &= ~(Bmod|Bimm);		putbuf(p);	}	/*	 * dont put written worm	 * blocks into free list	 */	if(nofree(dev, addr))		return;	p = getbuf(dev, superaddr(dev), Bread|Bmod);	if(!p || checktag(p, Tsuper, QPSUPER))		panic("bfree: super block");	addfree(dev, addr, (Superb*)p->iobuf);	putbuf(p);} longballoc(Device dev, int tag, long qid){	Iobuf *bp, *p;	Superb *sb;	long a;	int n; 	p = getbuf(dev, superaddr(dev), Bread|Bmod);	if(!p || checktag(p, Tsuper, QPSUPER))		panic("balloc: super block");	sb = (Superb*)p->iobuf; loop:	n = --sb->fbuf.nfree;	sb->tfree--;	if(n < 0 || n >= FEPERBUF)		panic("balloc: bad freelist");	a = sb->fbuf.free[n];	if(n <= 0) {		if(a == 0) {			sb->tfree = 0;			sb->fbuf.nfree = 1;			if(devgrow(dev, sb))				goto loop;			putbuf(p);			return 0;		}		bp = getbuf(dev, a, Bread);		if(!bp || checktag(bp, Tfree, QPNONE)) {			if(bp)				putbuf(bp);			putbuf(p);			return 0;		}		memmove(&sb->fbuf, bp->iobuf, (FEPERBUF+1)*sizeof(long));		putbuf(bp);	}	bp = getbuf(dev, a, Bmod);	memset(bp->iobuf, 0, RBUFSIZE);	settag(bp, tag, qid);	if(tag == Tind1 || tag == Tind2 || tag == Tdir)		bp->flags |= Bimm;	putbuf(bp);	putbuf(p);	return a;} voidaddfree(Device dev, long addr, Superb *sb){	int n;	Iobuf *p; 	if(addr >= sb->fsize){		print("addfree: bad addr %lux\n", addr);		return;	}	n = sb->fbuf.nfree;	if(n < 0 || n > FEPERBUF)		panic("addfree: bad freelist");

Lines 1–500 of 699.