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

1993/1115/port/chan.c (diff list | history)

port/chan.c on 1990/0227
1990/0227    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1990/0227    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1990/0227    
 
1992/0620    
struct 
{ 
1990/0227    
	Lock; 
1992/0620    
	int	fid; 
1993/0501    
	Chan	*free; 
	Chan	*list; 
1990/0227    
}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    
} 
 
int 
decref(Ref *r) 
{ 
1990/1104    
	int x; 
 
1990/0227    
	lock(r); 
1990/1104    
	x = --r->ref; 
1990/0227    
	unlock(r); 
1991/0723    
	if(x < 0)  
1991/0705    
		panic("decref"); 
1991/0723    
 
1990/1104    
	return x; 
1990/0227    
} 
 
void 
1993/0501    
chanrec(Mnt *m) 
{ 
	Chan *c; 
 
	lock(&chanalloc); 
	for(c = chanalloc.list; c; c = c->link) 
		if(c->mntptr == m) 
			c->flag |= CRECOV; 
	unlock(&chanalloc); 
} 
 
void 
1990/0227    
chandevreset(void) 
{ 
	int i; 
 
1993/0526    
	for(i=0; devchar[i]; i++) 
1990/0227    
		(*devtab[i].reset)(); 
} 
 
void 
chandevinit(void) 
{ 
	int i; 
 
1993/0526    
	for(i=0; devchar[i]; i++) 
1990/0227    
		(*devtab[i].init)(); 
} 
 
Chan* 
newchan(void) 
{ 
	Chan *c; 
 
1992/0620    
	lock(&chanalloc); 
	c = chanalloc.free; 
1993/0501    
	if(c != 0) 
1992/0620    
		chanalloc.free = c->next; 
	unlock(&chanalloc); 
 
	if(c == 0) { 
		c = smalloc(sizeof(Chan)); 
1993/0501    
		lock(&chanalloc); 
		c->fid = ++chanalloc.fid; 
		c->link = chanalloc.list; 
		chanalloc.list = c; 
		unlock(&chanalloc); 
1990/0227    
	} 
1992/0620    
 
	/* if you get an error before associating with a dev, 
	   close calls rootclose, a nop */ 
	c->type = 0; 
	c->flag = 0; 
	c->ref = 1; 
	c->dev = 0; 
	c->offset = 0; 
	c->mnt = 0; 
	c->aux = 0; 
	c->mchan = 0; 
1993/0501    
	c->path = 0; 
1993/1013    
	c->mcp = 0; 
1992/0620    
	c->mqid = (Qid){0, 0}; 
	return c; 
1990/0227    
} 
 
void 
1992/0320    
chanfree(Chan *c) 
{ 
	c->flag = CFREE; 
1993/0501    
 
1993/0330    
	if(c->session){ 
		freesession(c->session); 
		c->session = 0; 
	} 
1993/0501    
 
	/* 
	 * Channel can be closed before a path is created or the last 
	 * channel in a mount which has already cleared its pt names 
	 */ 
	if(c->path) 
		decref(c->path); 
 
1992/0320    
	lock(&chanalloc); 
	c->next = chanalloc.free; 
	chanalloc.free = c; 
	unlock(&chanalloc); 
} 
 
void 
1990/0227    
close(Chan *c) 
{ 
1993/0501    
	if(c->flag&CFREE) 
1990/0907    
		panic("close"); 
1991/1011    
 
1993/0501    
	if(decref(c)) 
		return; 
 
	if(!waserror()) { 
		(*devtab[c->type].close)(c); 
		poperror(); 
1990/0227    
	} 
1993/0501    
 
	chanfree(c); 
} 
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; 
} 
 
int 
1993/0501    
mount(Chan *new, Chan *old, int flag, char *spec) 
1990/0227    
{ 
	Pgrp *pg; 
1993/1115    
	int order, flg; 
1991/1011    
	Mhead *m, **l; 
1993/1115    
	Mount *nm, *f, *um, **h; 
1990/0227    
 
1990/11211    
	if(CHDIR & (old->qid.path^new->qid.path)) 
		error(Emount); 
1991/1011    
 
	order = flag&MORDER; 
 
	if((old->qid.path&CHDIR)==0 && order != MREPL) 
1990/11211    
		error(Emount); 
1990/0227    
 
1993/0501    
	pg = up->pgrp; 
1991/1011    
	wlock(&pg->ns); 
	if(waserror()) { 
		wunlock(&pg->ns); 
1990/0227    
		nexterror(); 
	} 
1991/1011    
 
	l = &MOUNTH(pg, old); 
	for(m = *l; m; m = m->hash) { 
		if(eqchan(m->from, old, 1)) 
			break; 
		l = &m->hash; 
1990/0227    
	} 
1991/1011    
 
	if(m == 0) { 
1992/0619    
		m = smalloc(sizeof(Mhead)); 
1991/1011    
		m->from = old; 
		incref(old); 
		m->hash = *l; 
		*l = m; 
		if(order != MREPL)  
1993/0501    
			m->mount = newmount(m, old, 0, 0); 
1990/0227    
	} 
 
1991/1011    
	if(m->mount && order == MREPL) { 
		mountfree(m->mount); 
		m->mount = 0; 
	} 
 
1993/0501    
	nm = newmount(m, new, flag, spec); 
1993/1115    
	if(new->mnt != 0) { 
		h = &nm->next; 
		for(um = new->mnt->next; um; um = um->next) { 
			flg = um->flag; 
			if(flg == 0) 
				flg = MAFTER; 
			f = newmount(m, um->to, flg, um->spec); 
			*h = f; 
			h = &f->next; 
		} 
	} 
1993/0501    
 
1990/0227    
	if(flag & MCREATE) 
		new->flag |= CCREATE; 
 
1991/1011    
	if(m->mount && order == MAFTER) { 
		for(f = m->mount; f->next; f = f->next) 
			; 
		f->next = nm; 
	} 
	else { 
1993/1115    
		for(f = nm; f->next; f = f->next) 
			; 
		f->next = m->mount; 
1991/1011    
		m->mount = nm; 
	} 
1990/0227    
 
1991/1011    
	wunlock(&pg->ns); 
	poperror(); 
	return nm->mountid; 
} 
1990/0227    
 
1991/1011    
void 
unmount(Chan *mnt, Chan *mounted) 
{ 
	Pgrp *pg; 
	Mhead *m, **l; 
	Mount *f, **p; 
 
1993/0501    
	pg = up->pgrp; 
1991/1011    
	wlock(&pg->ns); 
 
	l = &MOUNTH(pg, mnt); 
	for(m = *l; m; m = m->hash) { 
		if(eqchan(m->from, mnt, 1)) 
			break; 
		l = &m->hash; 
1990/0227    
	} 
 
1991/1011    
	if(m == 0) { 
		wunlock(&pg->ns); 
1992/0111    
		error(Eunmount); 
1990/0321    
	} 
1991/1011    
 
	if(mounted == 0) { 
		*l = m->hash; 
		wunlock(&pg->ns); 
		mountfree(m->mount); 
		close(m->from); 
1992/0619    
		free(m); 
1991/1011    
		return; 
	} 
 
	p = &m->mount; 
	for(f = *p; f; f = f->next) { 
1993/1111    
		if(eqchan(f->to, mounted, 1) || eqchan(f->to->mchan, mounted, 1)) { 
1991/1011    
			*p = f->next; 
			f->next = 0; 
			mountfree(f); 
			if(m->mount == 0) { 
				*l = m->hash; 
				wunlock(&pg->ns); 
				close(m->from); 
1992/0619    
				free(m); 
1991/1011    
				return; 
			} 
			wunlock(&pg->ns); 
			return; 
		} 
		p = &f->next; 
	} 
	wunlock(&pg->ns); 
1992/0111    
	error(Eunion); 
1990/0227    
} 
 
Chan* 
clone(Chan *c, Chan *nc) 
{ 
	return (*devtab[c->type].clone)(c, nc); 
} 
 
1991/0427    
Chan* 
domount(Chan *c) 
1990/0227    
{ 
	Pgrp *pg; 
1991/1011    
	Chan *nc; 
	Mhead *m; 
1990/0227    
 
1993/0501    
	pg = up->pgrp; 
1991/1011    
	rlock(&pg->ns); 
	if(waserror()) { 
		runlock(&pg->ns); 
1991/0427    
		nexterror(); 
	} 
1991/1011    
	c->mnt = 0; 
 
	for(m = MOUNTH(pg, c); m; m = m->hash) 
		if(eqchan(m->from, c, 1)) { 
			nc = clone(m->mount->to, 0); 
			nc->mnt = m->mount; 
1993/0501    
			nc->xmnt = nc->mnt; 
1991/1011    
			nc->mountid = m->mount->mountid; 
			close(c); 
			c = nc;	 
			break;			 
		} 
 
1991/0427    
	poperror(); 
1991/1011    
	runlock(&pg->ns); 
	return c; 
1990/0227    
} 
 
1991/0427    
Chan* 
1991/1011    
undomount(Chan *c) 
1990/0227    
{ 
1991/1011    
	Pgrp *pg; 
	Mhead **h, **he, *f; 
	Mount *t; 
1990/0227    
 
1993/0501    
	pg = up->pgrp; 
1991/1011    
	rlock(&pg->ns); 
	if(waserror()) { 
		runlock(&pg->ns); 
		nexterror(); 
1991/0427    
	} 
 
1991/1011    
	he = &pg->mnthash[MNTHASH]; 
	for(h = pg->mnthash; h < he; h++) { 
		for(f = *h; f; f = f->hash) { 
1992/0825    
			for(t = f->mount; t; t = t->next) { 
1991/1011    
				if(eqchan(c, t->to, 1)) { 
					close(c); 
					c = clone(t->head->from, 0); 
					break; 
				} 
1992/0825    
			} 
1991/0427    
		} 
1990/0914    
	} 
1991/1011    
	poperror(); 
	runlock(&pg->ns); 
	return c; 
} 
1990/0914    
 
1991/1011    
Chan* 
walk(Chan *ac, char *name, int domnt) 
{ 
	Pgrp *pg; 
1993/0501    
	Chan *c; 
1991/1011    
	Mount *f; 
	int dotdot; 
1990/0227    
 
1993/0501    
	if(name[0] == '\0') 
1991/1011    
		return ac; 
1990/0914    
 
1991/1011    
	dotdot = 0; 
1993/0501    
	if(name[0] == '.' && name[1] == '.' && name[2] == '\0') { 
1991/1011    
		ac = undomount(ac); 
		dotdot = 1; 
	} 
1991/0427    
 
1991/1011    
	if((*devtab[ac->type].walk)(ac, name) != 0) { 
		if(dotdot) 
			ac = undomount(ac); 
		if(domnt) 
			ac = domount(ac); 
		return ac; 
	} 
 
	if(ac->mnt == 0)  
		return 0; 
 
1993/0501    
	c = 0; 
	pg = up->pgrp; 
 
1991/1011    
	rlock(&pg->ns); 
	if(waserror()) { 
		runlock(&pg->ns); 
		if(c) 
			close(c); 
		nexterror(); 
	} 
	for(f = ac->mnt; f; f = f->next) { 
		c = clone(f->to, 0); 
		if((*devtab[c->type].walk)(c, name) != 0) 
			break; 
1990/0227    
		close(c); 
1991/1011    
		c = 0; 
	} 
	poperror(); 
	runlock(&pg->ns); 
 
1993/0501    
	if(c == 0) 
		return 0; 
 
	if(dotdot) 
		c = undomount(c); 
 
	c->mnt = 0; 
	if(domnt) { 
		if(waserror()) { 
			close(c); 
			nexterror(); 
1991/1011    
		} 
1993/0501    
		c = domount(c); 
		poperror(); 
1991/1011    
	} 
1993/0501    
	close(ac); 
1991/1011    
	return c;	 
1990/0227    
} 
 
/* 
1991/0427    
 * c is a mounted non-creatable directory.  find a creatable one. 
1990/0227    
 */ 
1991/0427    
Chan* 
createdir(Chan *c) 
1990/0227    
{ 
1991/1011    
	Pgrp *pg; 
	Chan *nc; 
	Mount *f; 
1990/0227    
 
1993/0501    
	pg = up->pgrp; 
1991/1011    
	rlock(&pg->ns); 
	if(waserror()) { 
		runlock(&pg->ns); 
1990/0227    
		nexterror(); 
	} 
1991/1011    
	for(f = c->mnt; f; f = f->next) { 
		if(f->to->flag&CCREATE) { 
			nc = clone(f->to, 0); 
			nc->mnt = f; 
			runlock(&pg->ns); 
1991/1126    
			poperror(); 
1991/1011    
			close(c); 
			return nc; 
		} 
1990/0227    
	} 
1991/1011    
	error(Enocreate); 
1992/0520    
	return 0;		/* not reached */ 
1990/0227    
} 
 
1993/0501    
Chan* 
mchan(char *id) 
{ 
	Chan *c; 
	Pgrp *pg; 
	Mount *t; 
	int mdev; 
	ulong mountid; 
	Mhead **h, **he, *f; 
 
	mountid = strtoul(id, 0, 0); 
	mdev = devno('M', 0); 
 
	pg = up->pgrp; 
	rlock(&pg->ns); 
	if(waserror()) { 
		runlock(&pg->ns); 
		nexterror(); 
	} 
 
	he = &pg->mnthash[MNTHASH]; 
	for(h = pg->mnthash; h < he; h++) { 
		for(f = *h; f; f = f->hash) { 
			for(t = f->mount; t; t = t->next) { 
				c = t->to; 
				if(c->type == mdev && c->mntptr->id == mountid) { 
					c = c->mntptr->c; 
					incref(c); 
					runlock(&pg->ns); 
					poperror(); 
					return c; 
				} 
			} 
		} 
	} 
	error(Enonexist); 
	return 0; 
} 
 
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) 
{ 
1992/1217    
	Rune r; 
1990/0821    
	char *p; 
1992/0711    
	char *elem; 
1993/0501    
	int t, n; 
	int mntok, isdot; 
	Chan *c, *nc, *cc; 
1991/1105    
	char createerr[ERRLEN]; 
1990/0227    
 
	if(name[0] == 0) 
1990/11211    
		error(Enonexist); 
1990/0821    
 
1993/0501    
	if(!((ulong)name & KZERO)) { 
1990/0821    
		p = name; 
		t = BY2PG-((ulong)p&(BY2PG-1)); 
1993/0501    
		while(vmemchr(p, 0, t) == 0) { 
1990/0821    
			p += t; 
			t = BY2PG; 
		} 
	} 
 
1993/0501    
	elem = up->elem; 
1990/0227    
	mntok = 1; 
1990/0820    
	isdot = 0; 
1993/0501    
	switch(name[0]) { 
	case '/': 
		c = clone(up->slash, 0); 
1990/0227    
		name = skipslash(name); 
1993/0501    
		break; 
	case '#': 
1990/0227    
		mntok = 0; 
1993/0501    
		elem[0] = 0; 
		n = 0; 
		while(*name && (*name != '/' || n < 2)) 
			elem[n++] = *name++; 
		elem[n] = '\0'; 
		n = chartorune(&r, elem+1)+1; 
		if(r == 'M') { 
1993/1114    
			if(amode != Aopen || omode != ORDWR) 
1993/0501    
				error(Eperm); 
1993/1114    
			name = skipslash(name); 
1993/0501    
			return mchan(elem+n); 
		} 
1992/1217    
		t = devno(r, 1); 
1990/0227    
		if(t == -1) 
1990/11211    
			error(Ebadsharp); 
1993/0501    
 
		c = (*devtab[t].attach)(elem+n); 
		name = skipslash(name); 
		break; 
	default: 
		c = clone(up->dot, 0); 
		name = skipslash(name); 
1990/0820    
		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    
 
1993/0501    
	while(*name) { 
		nc = walk(c, elem, mntok); 
		if(nc == 0) 
1990/11211    
			error(Enonexist); 
1991/0427    
		c = nc; 
1990/0227    
		name = nextelem(name, elem); 
	} 
1990/0820    
 
1993/1007    
	switch(amode) { 
1990/0227    
	case Aaccess: 
1993/1007    
		if(isdot) { 
1991/0427    
			c = domount(c); 
1993/1007    
			break; 
1990/0820    
		} 
1993/1007    
		nc = walk(c, elem, mntok); 
		if(nc == 0) 
			error(Enonexist); 
		c = nc; 
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. 
		 */ 
1993/0501    
		nc = walk(c, elem, 0); 
		if(nc == 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); 
1993/0501    
		else { 
			nc = walk(c, elem, mntok); 
			if(nc == 0) 
1990/11211    
				error(Enonexist); 
1991/0427    
			c = nc; 
1990/0820    
		} 
1990/0227    
	Open: 
1991/1011    
		/* else error() in open has wrong value of c saved */ 
1993/1018    
		saveregisters(); 
 
1993/1017    
		if(omode == OEXEC) 
1993/1018    
			c->flag &= ~CCACHE; 
	 
		c = (*devtab[c->type].open)(c, omode); 
 
1990/08141    
		if(omode & OCEXEC) 
1991/0427    
			c->flag |= CCEXEC; 
1992/0811    
		if(omode & ORCLOSE) 
			c->flag |= CRCLOSE; 
1990/0227    
		break; 
 
	case Amount: 
		/* 
1993/0501    
		 * When mounting on an already mounted upon directory, 
		 * one wants subsequent mounts to be attached to the  
		 * original directory, not the replacement. 
1990/0227    
		 */ 
1993/0501    
		nc = walk(c, elem, 0); 
		if(nc == 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(); 
		} 
1991/0727    
		nameok(elem); 
1993/0501    
		nc = walk(cc, elem, 1); 
		if(nc != 0) { 
1991/0427    
			poperror(); 
			close(c); 
			c = nc; 
1990/0227    
			omode |= OTRUNC; 
			goto Open; 
		} 
1991/0427    
		close(cc); 
		poperror(); 
 
		/* 
		 *  the file didn't exist, try the create 
		 */ 
1991/1011    
		if(c->mnt && !(c->flag&CCREATE)) 
1991/0427    
			c = createdir(c); 
1991/1105    
 
		/* 
1993/0501    
		 * protect against the open/create race. 
		 * This is not a complete fix. It just reduces the window. 
1991/1105    
		 */ 
		if(waserror()) { 
1993/0501    
			strcpy(createerr, up->error); 
1991/1105    
			nc = walk(c, elem, 1); 
			if(nc == 0) 
1992/0111    
				error(createerr); 
1991/1105    
			c = nc; 
			omode |= OTRUNC; 
			goto Open; 
		} 
1991/0427    
		(*devtab[c->type].create)(c, elem, omode, perm); 
1990/08141    
		if(omode & OCEXEC) 
1991/0427    
			c->flag |= CCEXEC; 
1991/1105    
		poperror(); 
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; 
} 
 
1992/0101    
char isfrog[256]={ 
1990/0227    
	/*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, 
}; 
1991/0727    
 
void 
nameok(char *elem) 
{ 
1991/1107    
	char *eelem; 
 
	eelem = elem+NAMELEN; 
1991/0727    
	while(*elem) { 
1992/0101    
		if(isfrog[*(uchar*)elem]) 
1991/0727    
			error(Ebadchar); 
		elem++; 
1991/1107    
		if(elem >= eelem) 
			error(Efilename); 
1991/0727    
	} 
} 
1990/0227    
 
/* 
 * name[0] should not be a slash. 
 */ 
char* 
nextelem(char *name, char *elem) 
{ 
1992/0711    
	int w; 
1993/0501    
	char *end; 
1992/0213    
	Rune r; 
1990/0227    
 
	if(*name == '/') 
1990/11211    
		error(Efilename); 
1993/0501    
	end = utfrune(name, '/'); 
	if(end == 0) 
		end = strchr(name, 0); 
	w = end-name; 
1992/0213    
	if(w >= NAMELEN) 
		error(Efilename); 
	memmove(elem, name, w); 
	elem[w] = 0; 
1993/0501    
	while(name < end){ 
1992/0213    
		name += chartorune(&r, name); 
		if(r<sizeof(isfrog) && isfrog[r]) 
1990/11211    
			error(Ebadchar); 
1990/0227    
	} 
	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)