plan 9 kernel history: overview | file list | diff list

1991/0705/port/chan.c (diff list | history)

1991/0705/sys/src/9/port/chan.c:1,7021991/0722/sys/src/9/port/chan.c:1,715 (short | long | prev | next)
1990/0227    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"errno.h" 
 
 
struct{ 
	Lock; 
	Chan	*free; 
}chanalloc; 
 
int 
incref(Ref *r) 
{ 
1990/1104    
	int x; 
 
1990/0227    
	lock(r); 
1990/1104    
	x = ++r->ref; 
1990/0227    
	unlock(r); 
1990/1104    
	return x; 
1990/0227    
} 
 
1991/0722    
#include "ureg.h" 
 
1990/0227    
int 
decref(Ref *r) 
{ 
1990/1104    
	int x; 
1991/0722    
	int i; 
	Segment *s; 
1990/1104    
 
1990/0227    
	lock(r); 
1990/1104    
	x = --r->ref; 
1990/0227    
	unlock(r); 
1991/0705    
	if(x < 0) 
1991/0722    
	if(x < 0) { 
		if(u) { 
			print("%d: %s %lux %lux\n", u->p->pid, u->p->text, *(ulong*)((Ureg*)UREGADDR)->pc, r); 
			for(i = 0; i < NSEG; i++) { 
				s = u->p->seg[i]; 
				if(s) 
					print("%d: %lux %lux %lux", i, s, s->base, s->top); 
			} 
		} 
1991/0705    
		panic("decref"); 
1991/0722    
	} 
1990/1104    
	return x; 
1990/0227    
} 
 
void 
chaninit(void) 
{ 
	int i; 
	Chan *c; 
 
	chanalloc.free = ialloc(conf.nchan*sizeof(Chan), 0); 
 
	c = chanalloc.free; 
	for(i=0; i<conf.nchan-1; i++,c++){ 
		c->fid = i; 
		c->next = c+1; 
	} 
	c->next = 0; 
} 
 
void 
chandevreset(void) 
{ 
	int i; 
 
	for(i=0; i<strlen(devchar); i++) 
		(*devtab[i].reset)(); 
} 
 
void 
chandevinit(void) 
{ 
	int i; 
 
	for(i=0; i<strlen(devchar); i++) 
		(*devtab[i].init)(); 
} 
 
Chan* 
newchan(void) 
{ 
	Chan *c; 
 
loop: 
	lock(&chanalloc); 
	if(c = chanalloc.free){		/* assign = */ 
		chanalloc.free = c->next; 
1990/0707    
		c->type = 0;	/* if closed before changed, this calls rooterror, a nop */ 
1990/0227    
		c->flag = 0; 
		c->ref = 1; 
		unlock(&chanalloc); 
1990/11211    
		c->dev = 0; 
1990/0227    
		c->offset = 0; 
		c->mnt = 0; 
1991/0427    
		c->stream = 0; 
1991/0421    
		c->aux = 0; 
1991/0427    
		c->mntindex = 0; 
1990/0303    
		c->mchan = 0; 
1990/11211    
		c->mqid = (Qid){0, 0}; 
1990/0227    
		return c; 
	} 
	unlock(&chanalloc); 
	print("no chans\n"); 
	if(u == 0) 
		panic("newchan"); 
	u->p->state = Wakeme; 
	alarm(1000, wakeme, u->p); 
	sched(); 
	goto loop; 
} 
 
void 
close(Chan *c) 
{ 
1990/0907    
	if(c->flag & CFREE) 
		panic("close"); 
1990/0227    
	if(decref(c) == 0){ 
1991/0414    
		if(!waserror()) { 
			(*devtab[c->type].close)(c); 
			poperror(); 
1990/0227    
		} 
1991/0414    
		c->flag = CFREE; 
		lock(&chanalloc); 
		c->next = chanalloc.free; 
		chanalloc.free = c; 
		unlock(&chanalloc); 
1990/0227    
	} 
} 
 
int 
1990/11211    
eqqid(Qid a, Qid b) 
1990/0227    
{ 
1990/11211    
	return a.path==b.path && a.vers==b.vers; 
} 
 
int 
eqchan(Chan *a, Chan *b, int pathonly) 
{ 
	if(a->qid.path != b->qid.path) 
1990/0227    
		return 0; 
1990/11211    
	if(!pathonly && a->qid.vers!=b->qid.vers) 
		return 0; 
1990/0227    
	if(a->type != b->type) 
		return 0; 
	if(a->dev != b->dev) 
		return 0; 
	return 1; 
} 
 
/* 
 * omnt is locked.  return with nmnt locked. 
 */ 
Mount* 
mountsplit(Mount *omnt) 
{ 
	Mount *nmnt; 
 
	nmnt = newmount(); 
	lock(nmnt); 
	nmnt->term = omnt->term; 
	nmnt->mountid = omnt->mountid; 
	nmnt->next = omnt->next; 
	if(nmnt->next) 
1990/0603    
		incref(nmnt->next); 
1990/0227    
	nmnt->c = omnt->c; 
	incref(nmnt->c); 
	omnt->ref--; 
	unlock(omnt); 
	return nmnt; 
} 
 
int 
mount(Chan *new, Chan *old, int flag) 
{ 
	int i; 
	Mtab *mt, *mz; 
	Mount *mnt, *omnt, *nmnt, *pmnt; 
	Pgrp *pg; 
1990/0321    
	int islast; 
1990/0227    
 
1990/11211    
	if(CHDIR & (old->qid.path^new->qid.path)) 
		error(Emount); 
	if((old->qid.path&CHDIR)==0 && (flag&MORDER)!=MREPL) 
		error(Emount); 
1990/0227    
 
	mz = 0; 
1990/0321    
	islast = 0; 
	mnt = 0; 
1990/0227    
	pg = u->p->pgrp; 
	lock(pg); 
	if(waserror()){ 
1990/0321    
		if(mnt){ 
			mnt->c = 0;	/* caller will close new */ 
			closemount(mnt); 
		} 
1990/0227    
		unlock(pg); 
		nexterror(); 
	} 
	/* 
	 * Is old already in mount table? 
	 */ 
	mt = pg->mtab; 
	for(i=0; i<pg->nmtab; i++,mt++){ 
		if(mt->c==0 && mz==0) 
			mz = mt; 
1990/1122    
		else if(eqchan(mt->c, old, 1)){ 
1990/0321    
			mz = 0; 
1990/0227    
			goto Found; 
1990/0321    
		} 
1990/0227    
	} 
	if(mz == 0){ 
		if(i == conf.nmtab) 
1990/11211    
			error(Enomount); 
1990/0227    
		mz = &pg->mtab[i]; 
1990/0321    
		islast++; 
1990/0227    
	} 
	mz->mnt = 0; 
	mt = mz; 
 
    Found: 
	new->flag = CMOUNT; 
	if(flag & MCREATE) 
		new->flag |= CCREATE; 
	mnt = newmount(); 
	mnt->c = new; 
 
	switch(flag & MORDER){ 
	/* 
	 * These two always go at head of list 
	 */ 
	case MBEFORE: 
		if(mt->mnt == 0) 
1990/11211    
			error(Enotunion); 
1990/0227    
		/* fall through */ 
 
	case MREPL: 
1990/0603    
		mnt->next = mt->mnt; 
1990/0227    
		mt->mnt = mnt; 
		if((flag&MORDER) == MBEFORE) 
			mnt->term = 0; 
1990/0603    
		else 
			mnt->term = 1; 
1990/0227    
		break; 
 
	/* 
	 * This one never goes at head of list 
	 */ 
	case MAFTER: 
		if(mt->mnt == 0) 
1990/11211    
			error(Enotunion); 
1990/0227    
		omnt = mt->mnt; 
		pmnt = 0; 
		while(!omnt->term){ 
			lock(omnt); 
			if(omnt->ref > 1){ 
				omnt = mountsplit(omnt); 
				if(pmnt) 
					pmnt->next = omnt; 
				else 
					mt->mnt = omnt; 
			} 
			unlock(omnt); 
			nmnt = omnt->next; 
			if(nmnt == 0) 
				panic("MAFTER term"); 
			pmnt = omnt; 
			omnt = nmnt; 
		} 
		mnt->next = omnt->next; 
		omnt->next = mnt; 
		mnt->term = 1; 
		omnt->term = 0; 
		break; 
	} 
 
	incref(new); 
1990/0321    
	if(mz){ 
		mz->c = old; 
1990/0227    
		incref(old); 
1990/0321    
	} 
	if(islast) 
		pg->nmtab++; 
1990/0227    
	unlock(pg); 
	poperror(); 
	return mnt->mountid; 
} 
 
Chan* 
clone(Chan *c, Chan *nc) 
{ 
	return (*devtab[c->type].clone)(c, nc); 
} 
 
1991/0427    
Chan* 
domount(Chan *c) 
1990/0227    
{ 
	int i; 
1991/0427    
	ulong mntid; 
1990/0227    
	Mtab *mt; 
1991/0427    
	Mount *mnt; 
1990/0227    
	Pgrp *pg; 
1991/0427    
	Chan *nc, *mc; 
1990/0227    
 
	pg = u->p->pgrp; 
	/* 
	 * Is c in in mount table? 
	 */ 
	mt = pg->mtab; 
	for(i=0; i<pg->nmtab; i++,mt++) 
1991/0427    
		if(mt->c && eqchan(mt->c, c, 1)) 
1990/0227    
			goto Found; 
	/* 
	 * No; c is unaffected 
	 */ 
1991/0427    
	return c; 
1990/0227    
 
	/* 
	 * Yes; move c through table 
	 */ 
    Found: 
	lock(pg); 
1991/0427    
	if(!eqchan(mt->c, c, 1)){	/* table changed underfoot */ 
1990/0321    
		pprint("domount: changed underfoot?\n"); 
1990/0227    
		unlock(pg); 
1991/0427    
		return c; 
1990/0227    
	} 
1991/0427    
	mnt = mt->mnt; 
	mntid = mnt->mountid; 
	mc = mnt->c; 
1990/0227    
	incref(mc); 
	unlock(pg); 
1991/0427    
	if(waserror()){ 
		close(mc); 
		nexterror(); 
	} 
	nc = clone(mc, 0); 
	close(mc); 
	poperror(); 
	close(c); 
	nc->mnt = mnt; 
	nc->mountid = mntid; 
	return nc; 
1990/0227    
} 
 
1991/0427    
Chan* 
walk(Chan *ac, char *name, int domnt) 
1990/0227    
{ 
1991/0427    
	Mount *mnt; 
1990/0227    
	int first = 1; 
1991/0427    
	Chan *c = ac; 
	Chan *nc, *mc; 
1990/0227    
	Pgrp *pg = u->p->pgrp; 
 
	/* 
	 * name may be empty if the file name is "/", "#c" etc. 
	 */ 
1991/0427    
    Again: 
	if(name[0] && (*devtab[c->type].walk)(c, name)==0){ 
		if(!(c->flag&CMOUNT)) 
			goto Notfound; 
		mnt = c->mnt; 
		if(mnt == 0) 
			panic("walk"); 
		lock(pg); 
		if(mnt->term){ 
1990/0227    
			unlock(pg); 
1991/0427    
			goto Notfound; 
1990/0914    
		} 
1991/0427    
		if(c->mountid != mnt->mountid){ 
			pprint("walk: changed underfoot? '%s'\n", name); 
			unlock(pg); 
			goto Notfound; 
		} 
		mnt = mnt->next; 
		mc = mnt->c; 
		incref(mc); 
		unlock(pg); 
		if(waserror()){ 
			close(mc); 
			nexterror(); 
		} 
		if(mnt == 0) 
			panic("walk 1"); 
		nc = clone(mc, 0); 
		close(mc); 
		poperror(); 
1991/0423    
		if(!first) 
1991/0427    
			close(c); 
		nc->mnt = mnt; 
		nc->mountid = mnt->mountid; 
		c = nc; 
		first = 0; 
		goto Again; 
	} 
 
	if(name[0])			/* walk succeeded */ 
1991/0423    
		c->flag &= ~CMOUNT; 
1991/0427    
 
	if(domnt){ 
		if(waserror()){ 
			if(!first) 
				close(c); 
			return 0; 
		} 
		c = domount(c); 
		poperror(); 
1990/0914    
	} 
 
1991/0427    
	if(!first) 
		close(ac); 
1990/0227    
 
1990/0914    
 
1991/0427    
	return c; 
 
1990/0227    
    Notfound: 
	if(!first) 
		close(c); 
	return 0; 
} 
 
/* 
1991/0427    
 * c is a mounted non-creatable directory.  find a creatable one. 
1990/0227    
 */ 
1991/0427    
Chan* 
createdir(Chan *c) 
1990/0227    
{ 
	Mount *mnt; 
	Pgrp *pg = u->p->pgrp; 
1991/0427    
	Chan *mc, *nc; 
1990/0227    
 
	lock(pg); 
	if(waserror()){ 
		unlock(pg); 
		nexterror(); 
	} 
1991/0427    
	mnt = c->mnt; 
	if(c->mountid != mnt->mountid){ 
1990/0321    
		pprint("createdir: changed underfoot?\n"); 
1990/11211    
		error(Enocreate); 
1990/0227    
	} 
	do{ 
		if(mnt->term) 
1990/11211    
			error(Enocreate); 
1990/0227    
		mnt = mnt->next; 
	}while(!(mnt->c->flag&CCREATE)); 
	mc = mnt->c; 
	incref(mc); 
	unlock(pg); 
1991/0427    
	if(waserror()){ 
		close(mc); 
		nexterror(); 
	} 
	nc = clone(mc, 0); 
1990/0227    
	poperror(); 
1991/0427    
	close(c); 
	close(mc); 
	nc->mnt = mnt; 
	return nc; 
1990/0227    
} 
 
1990/0914    
void 
saveregisters(void) 
{ 
} 
 
1990/0227    
/* 
 * Turn a name into a channel. 
 * &name[0] is known to be a valid address.  It may be a kernel address. 
 */ 
Chan* 
namec(char *name, int amode, int omode, ulong perm) 
{ 
1991/0427    
	Chan *c, *nc, *cc; 
1990/0227    
	int t; 
1990/0820    
	int mntok, isdot; 
1990/0821    
	char *p; 
	char *elem; 
1990/0227    
 
	if(name[0] == 0) 
1990/11211    
		error(Enonexist); 
1990/0821    
 
	/* 
	 * Make sure all of name is o.k.  first byte is validated 
	 * externally so if it's a kernel address we know it's o.k. 
	 */ 
	if(!((ulong)name & KZERO)){ 
		p = name; 
		t = BY2PG-((ulong)p&(BY2PG-1)); 
		while(vmemchr(p, 0, t) == 0){ 
			p += t; 
			t = BY2PG; 
		} 
	} 
 
	elem = u->elem; 
1990/0227    
	mntok = 1; 
1990/0820    
	isdot = 0; 
1990/0227    
	if(name[0] == '/'){ 
1991/0427    
		c = clone(u->slash, 0); 
1990/0227    
		/* 
		 * Skip leading slashes. 
		 */ 
		name = skipslash(name); 
	}else if(name[0] == '#'){ 
		mntok = 0; 
1990/1009    
		if(name[1]=='M') 
1990/11211    
			error(Enonexist); 
1990/0227    
		t = devno(name[1], 1); 
		if(t == -1) 
1990/11211    
			error(Ebadsharp); 
1990/0227    
		name += 2; 
		if(*name == '/'){ 
			name = skipslash(name); 
			elem[0]=0; 
		}else 
			name = nextelem(name, elem); 
1991/0427    
		c = (*devtab[t].attach)(elem); 
1990/0820    
	}else{ 
1991/0427    
		c = clone(u->dot, 0); 
1990/0820    
		name = skipslash(name);	/* eat leading ./ */ 
		if(*name == 0) 
			isdot = 1; 
	} 
1990/0227    
 
	if(waserror()){ 
1991/0427    
		close(c); 
1990/0227    
		nexterror(); 
	} 
 
	name = nextelem(name, elem); 
1990/0820    
 
1991/0416    
	/* 
	 *  If mounting, don't follow the mount entry for root or the 
	 *  current directory. 
	 */ 
	if(mntok && !isdot && !(amode==Amount && elem[0]==0)) 
1991/0427    
		c = domount(c);			/* see case Atodir below */ 
1990/0227    
 
	/* 
	 * How to treat the last element of the name depends on the operation. 
	 * Therefore do all but the last element by the easy algorithm. 
	 */ 
	while(*name){ 
1991/0427    
		if((nc=walk(c, elem, mntok)) == 0) 
1990/11211    
			error(Enonexist); 
1991/0427    
		c = nc; 
1990/0227    
		name = nextelem(name, elem); 
	} 
1990/0820    
 
1990/0227    
	/* 
	 * Last element; act according to type of access. 
	 */ 
	switch(amode){ 
	case Aaccess: 
1990/0820    
		if(isdot) 
1991/0427    
			c = domount(c); 
1990/0820    
		else{ 
1991/0427    
			if((nc=walk(c, elem, mntok)) == 0) 
1990/11211    
				error(Enonexist); 
1991/0427    
			c = nc; 
1990/0820    
		} 
1990/0227    
		break; 
 
	case Atodir: 
		/* 
		 * Directories (e.g. for cd) are left before the mount point, 
		 * so one may mount on / or . and see the effect. 
		 */ 
1991/0427    
		if((nc=walk(c, elem, 0)) == 0) 
1990/11211    
			error(Enonexist); 
1991/0427    
		c = nc; 
		if(!(c->qid.path & CHDIR)) 
1990/11211    
			error(Enotdir); 
1990/0227    
		break; 
 
	case Aopen: 
1990/0820    
		if(isdot) 
1991/0427    
			c = domount(c); 
1990/0820    
		else{ 
1991/0427    
			if((nc=walk(c, elem, mntok)) == 0) 
1990/11211    
				error(Enonexist); 
1991/0427    
			c = nc; 
1990/0820    
		} 
1990/0227    
	Open: 
1991/0427    
		saveregisters();	/* else error() in open has wrong value of c saved */ 
		c = (*devtab[c->type].open)(c, omode); 
1990/08141    
		if(omode & OCEXEC) 
1991/0427    
			c->flag |= CCEXEC; 
1990/0227    
		break; 
 
	case Amount: 
		/* 
		 * When mounting on an already mounted upon directory, one wants 
		 * the second mount to be attached to the original directory, not 
		 * the replacement. 
		 */ 
1991/0427    
		if((nc=walk(c, elem, 0)) == 0) 
1990/11211    
			error(Enonexist); 
1991/0427    
		c = nc; 
1990/0227    
		break; 
 
	case Acreate: 
1990/0820    
		if(isdot) 
1990/11211    
			error(Eisdir); 
1991/0427    
 
		/* 
		 *  Walk the element before trying to create it 
		 *  to see if it exists.  We clone the channel 
		 *  first, just in case someone is trying to 
		 *  use clwalk outside the kernel. 
		 */ 
		cc = clone(c, 0); 
		if(waserror()){ 
			close(cc); 
			nexterror(); 
		} 
		if((nc=walk(cc, elem, 1)) != 0){ 
			poperror(); 
			close(c); 
			c = nc; 
1990/0227    
			omode |= OTRUNC; 
			goto Open; 
		} 
1991/0427    
		close(cc); 
		poperror(); 
 
		/* 
		 *  the file didn't exist, try the create 
		 */ 
		if((c->flag&(CMOUNT|CCREATE)) == CMOUNT) 
			c = createdir(c); 
		(*devtab[c->type].create)(c, elem, omode, perm); 
1990/08141    
		if(omode & OCEXEC) 
1991/0427    
			c->flag |= CCEXEC; 
1990/0227    
		break; 
 
	default: 
		panic("unknown namec access %d\n", amode); 
	} 
	poperror(); 
1991/0427    
	return c; 
1990/0227    
} 
 
/* 
 * name[0] is addressable. 
 */ 
char* 
skipslash(char *name) 
{ 
1990/0820    
    Again: 
1990/0821    
	while(*name == '/') 
1990/0227    
		name++; 
1990/0821    
	if(*name=='.' && (name[1]==0 || name[1]=='/')){ 
		name++; 
		goto Again; 
1990/0820    
	} 
1990/0227    
	return name; 
} 
 
char isfrog[]={ 
	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1, 
	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1, 
	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1, 
	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1, 
	[' ']	1, 
	['/']	1, 
	[0x7f]	1, 
}; 
 
/* 
 * name[0] should not be a slash. 
 * Advance name to next element in path, copying current element into elem. 
 * Return pointer to next element, skipping slashes. 
 */ 
char* 
nextelem(char *name, char *elem) 
{ 
	int i, user, c; 
	char *end, *e; 
 
	if(*name == '/') 
1990/11211    
		error(Efilename); 
1990/0821    
	end = memchr(name, 0, NAMELEN); 
1990/0227    
	if(end == 0){ 
1990/0821    
		end = memchr(name, '/', NAMELEN); 
1990/0227    
		if(end == 0) 
1990/11211    
			error(Efilename); 
1990/0227    
	}else{ 
		e = memchr(name, '/', end-name); 
		if(e) 
			end = e; 
	} 
	while(name < end){ 
		c = *name++; 
		if((c&0x80) || isfrog[c]) 
1990/11211    
			error(Ebadchar); 
1990/0227    
		*elem++ = c; 
	} 
	*elem = 0; 
	return skipslash(name); 
} 
 
void 
isdir(Chan *c) 
{ 
1990/11211    
	if(c->qid.path & CHDIR) 
1990/0227    
		return; 
1990/11211    
	error(Enotdir); 
1990/0227    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)