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

2002/0615/port/devmnt.c (diff list | history)

port/devmnt.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    
 
2001/0819    
/* 
 * References are managed as follows: 
 * The channel to the server - a network connection or pipe - has one 
 * reference for every Chan open on the server.  The server channel has 
 * c->mux set to the Mnt used for muxing control to that server.  Mnts 
 * have no reference count; they go away when c goes away. 
 * Each channel derived from the mount point has mchan set to c, 
 * and increfs/decrefs mchan to manage references on the server 
 * connection. 
 */ 
 
2001/0527    
#define MAXRPC (IOHDRSZ+8192) 
 
1991/0911    
struct Mntrpc 
1990/0227    
{ 
1995/0107    
	Chan*	c;		/* Channel for whom we are working */ 
	Mntrpc*	list;		/* Free/pending list */ 
1991/0911    
	Fcall	request;	/* Outgoing file system protocol message */ 
2001/0619    
	Fcall 	reply;		/* Incoming reply */ 
1995/0107    
	Mnt*	m;		/* Mount device during rpc */ 
1991/0911    
	Rendez	r;		/* Place to hang out */ 
2001/0527    
	uchar*	rpc;		/* I/O Data buffer */ 
2001/0819    
	uint		rpclen;	/* len of buffer */ 
2001/0619    
	Block	*b;		/* reply blocks */ 
1991/0911    
	char	done;		/* Rpc completed */ 
1998/0917    
	uvlong	stime;		/* start time for mnt statistics */ 
	ulong	reqlen;		/* request length for mnt statistics */ 
	ulong	replen;		/* reply length for mnt statistics */ 
2000/0105    
	Mntrpc*	flushed;	/* message this one flushes */ 
1990/0227    
}; 
 
1991/0911    
struct Mntalloc 
1990/0227    
{ 
	Lock; 
1995/0107    
	Mnt*	list;		/* Mount devices in use */ 
	Mnt*	mntfree;	/* Free list */ 
	Mntrpc*	rpcfree; 
1999/0212    
	int	nrpcfree; 
	int	nrpcused; 
1994/1124    
	ulong	id; 
1992/0620    
	int	rpctag; 
1991/0911    
}mntalloc; 
1990/0227    
 
2001/0527    
void	mattach(Mnt*, Chan*, char*); 
Mnt*	mntchk(Chan*); 
void	mntdirfix(uchar*, Chan*); 
Mntrpc*	mntflushalloc(Mntrpc*, ulong); 
void	mntflushfree(Mnt*, Mntrpc*); 
void	mntfree(Mntrpc*); 
void	mntgate(Mnt*); 
void	mntpntfree(Mnt*); 
void	mntqrm(Mnt*, Mntrpc*); 
Mntrpc*	mntralloc(Chan*, ulong); 
long	mntrdwr(int, Chan*, void*, long, vlong); 
int	mntrpcread(Mnt*, Mntrpc*); 
void	mountio(Mnt*, Mntrpc*); 
void	mountmux(Mnt*, Mntrpc*); 
void	mountrpc(Mnt*, Mntrpc*); 
int	rpcattn(void*); 
Chan*	mntchan(void); 
1990/0227    
 
2001/0527    
char	Esbadstat[] = "invalid directory entry received from server"; 
2001/0819    
char Enoversion[] = "version not established for mount channel"; 
2001/0527    
 
1998/0917    
void (*mntstats)(int, Chan*, uvlong, ulong); 
1994/0513    
 
1991/0911    
enum 
1990/0303    
{ 
1993/1011    
	Tagspace	= 1, 
1991/0911    
}; 
1990/0604    
 
1997/0327    
static void 
1991/0911    
mntreset(void) 
1990/0227    
{ 
1991/0911    
	mntalloc.id = 1; 
1992/0620    
	mntalloc.rpctag = Tagspace; 
2002/0217    
	fmtinstall('F', fcallfmt); 
	fmtinstall('D', dirfmt); 
2002/0615    
/*	fmtinstall('M', dirmodefmt);  No!  Clashes with eipfmt [sape] */ 
1993/1015    
 
	cinit(); 
1990/0604    
} 
 
2001/0819    
/* 
 * Version is not multiplexed: message sent only once per connection. 
 */ 
long 
mntversion(Chan *c, char *version, int msize, int returnlen) 
1990/0227    
{ 
2001/0819    
	Fcall f; 
	uchar *msg; 
1992/0620    
	Mnt *m; 
2001/0819    
	char *v; 
	long k, l; 
	uvlong oo; 
	char buf[128]; 
1990/0227    
 
2001/0819    
	qlock(&c->umqlock);	/* make sure no one else does this until we've established ourselves */ 
	if(waserror()){ 
		qunlock(&c->umqlock); 
		nexterror(); 
	} 
1992/0620    
 
2001/0819    
	/* defaults */ 
	if(msize == 0) 
2001/0820    
		msize = MAXRPC; 
	if(msize > c->iounit && c->iounit != 0) 
		msize = c->iounit; 
2001/0819    
	v = version; 
	if(v == nil || v[0] == '\0') 
		v = VERSION9P; 
 
	/* validity */ 
	if(msize < 0) 
		error("bad iounit in version call"); 
	if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0) 
		error("bad 9P version specification"); 
 
	m = c->mux; 
 
	if(m != nil){ 
		qunlock(&c->umqlock); 
		poperror(); 
 
		strecpy(buf, buf+sizeof buf, m->version); 
		k = strlen(buf); 
		if(strncmp(buf, v, k) != 0){ 
			snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v); 
			error(buf); 
1991/0911    
		} 
2001/0819    
		if(returnlen > 0){ 
			if(returnlen < k) 
				error(Eshort); 
			memmove(version, buf, k); 
		} 
		return k; 
1991/0901    
	} 
1993/1015    
 
2001/0819    
	f.type = Tversion; 
	f.tag = NOTAG; 
	f.msize = msize; 
	f.version = v; 
	msg = malloc(8192+IOHDRSZ); 
	if(msg == nil) 
		exhausted("version memory"); 
	if(waserror()){ 
		free(msg); 
		nexterror(); 
	} 
	k = convS2M(&f, msg, 8192+IOHDRSZ); 
	if(k == 0) 
		error("bad fversion conversion on send"); 
 
	lock(c); 
	oo = c->offset; 
	c->offset += k; 
	unlock(c); 
 
	l = devtab[c->type]->write(c, msg, k, oo); 
 
	if(l < k){ 
		lock(c); 
		c->offset -= k - l; 
		unlock(c); 
		error("short write in fversion"); 
	} 
 
	/* message sent; receive and decode reply */ 
	k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset); 
	if(k <= 0) 
		error("EOF receiving fversion reply"); 
 
	lock(c); 
	c->offset += k; 
	unlock(c); 
 
	l = convM2S(msg, k, &f); 
	if(l != k) 
		error("bad fversion conversion on reply"); 
2001/0918    
	if(f.type != Rversion){ 
		if(f.type == Rerror) 
			error(f.ename); 
2001/0819    
		error("unexpected reply type in fversion"); 
2001/0918    
	} 
2001/0819    
	if(f.msize > msize) 
		error("server tries to increase msize in fversion"); 
	if(f.msize<256 || f.msize>1024*1024) 
		error("nonsense value of msize in fversion"); 
	if(strncmp(f.version, v, strlen(f.version)) != 0) 
		error("bad 9P version returned from server"); 
 
	/* now build Mnt associated with this connection */ 
	lock(&mntalloc); 
1991/0911    
	m = mntalloc.mntfree; 
1992/0620    
	if(m != 0) 
1998/0512    
		mntalloc.mntfree = m->list; 
1992/0620    
	else { 
		m = malloc(sizeof(Mnt)); 
		if(m == 0) { 
			unlock(&mntalloc); 
			exhausted("mount devices"); 
		} 
	} 
	m->list = mntalloc.list; 
	mntalloc.list = m; 
2001/0820    
	m->version = nil; 
2001/0819    
	kstrdup(&m->version, f.version); 
1991/0911    
	m->id = mntalloc.id++; 
2001/0619    
	m->q = qopen(10*MAXRPC, 0, nil, nil); 
2001/0820    
	m->msize = f.msize; 
1991/0911    
	unlock(&mntalloc); 
1992/0620    
 
2001/0819    
	poperror();	/* msg */ 
	free(msg); 
 
1997/1205    
	lock(m); 
1991/0911    
	m->queue = 0; 
	m->rip = 0; 
2001/0819    
 
	c->flag |= CMSG; 
	c->mux = m; 
1992/0620    
	m->c = c; 
2001/0819    
	unlock(m); 
1991/0911    
 
2001/0819    
	poperror();	/* c */ 
	qunlock(&c->umqlock); 
1993/0501    
 
2001/0819    
	k = strlen(f.version); 
	if(returnlen > 0){ 
		if(returnlen < k) 
			error(Eshort); 
		memmove(version, f.version, k); 
	} 
1990/0604    
 
2001/0819    
	return k; 
} 
 
Chan* 
mntauth(Chan *c, char *spec) 
{ 
	Mnt *m; 
	Mntrpc *r; 
 
	m = c->mux; 
 
	if(m == nil){ 
		mntversion(c, VERSION9P, MAXRPC, 0); 
		m = c->mux; 
		if(m == nil) 
			error(Enoversion); 
	} 
 
1993/0501    
	c = mntchan(); 
1992/0320    
	if(waserror()) { 
2001/0527    
		/* Close must not be called since it will 
		 * call mnt recursively 
		 */ 
		chanfree(c); 
1992/0320    
		nexterror(); 
	} 
 
2001/0820    
	r = mntralloc(0, m->msize); 
1993/0321    
 
2001/0819    
	if(waserror()) { 
		mntfree(r); 
		nexterror(); 
	} 
1993/1016    
 
2001/0819    
	r->request.type = Tauth; 
	r->request.afid = c->fid; 
	r->request.uname = up->user; 
	r->request.aname = spec; 
	mountrpc(m, r); 
1990/0604    
 
2001/0819    
	c->qid = r->reply.aqid; 
	c->mchan = m->c; 
	incref(m->c); 
	c->mqid = c->qid; 
	c->mode = ORDWR; 
1991/0911    
 
2001/0819    
	poperror();	/* r */ 
	mntfree(r); 
1993/0501    
 
2001/0819    
	poperror();	/* c */ 
 
1993/0501    
	return c; 
2001/0819    
 
1993/0501    
} 
 
2001/0819    
static Chan* 
mntattach(char *muxattach) 
1993/0501    
{ 
2001/0819    
	Mnt *m; 
	Chan *c; 
1993/0501    
	Mntrpc *r; 
2001/0819    
	struct bogus{ 
		Chan	*chan; 
		Chan	*authchan; 
		char	*spec; 
		int	flags; 
	}bogus; 
1993/0501    
 
2001/0819    
	bogus = *((struct bogus *)muxattach); 
	c = bogus.chan; 
 
	m = c->mux; 
 
	if(m == nil){ 
		mntversion(c, nil, 0, 0); 
		m = c->mux; 
		if(m == nil) 
			error(Enoversion); 
	} 
 
	c = mntchan(); 
	if(waserror()) { 
		/* Close must not be called since it will 
		 * call mnt recursively 
		 */ 
		chanfree(c); 
		nexterror(); 
	} 
 
2001/0820    
	r = mntralloc(0, m->msize); 
1991/0911    
 
1994/1212    
	if(waserror()) { 
1992/0314    
		mntfree(r); 
		nexterror(); 
	} 
 
1991/0911    
	r->request.type = Tattach; 
	r->request.fid = c->fid; 
2001/0819    
	if(bogus.authchan == nil) 
		r->request.afid = NOFID; 
	else 
		r->request.afid = bogus.authchan->fid; 
2001/0527    
	r->request.uname = up->user; 
2001/0819    
	r->request.aname = bogus.spec; 
1991/0911    
	mountrpc(m, r); 
 
	c->qid = r->reply.qid; 
	c->mchan = m->c; 
2001/0819    
	incref(m->c); 
1990/0303    
	c->mqid = c->qid; 
1993/0501    
 
2001/0819    
	poperror();	/* r */ 
1991/0911    
	mntfree(r); 
2001/0819    
 
	poperror();	/* c */ 
 
	if(bogus.flags&MCACHE) 
		c->flag |= CCACHE; 
	return c; 
1992/0318    
} 
 
2001/0819    
Chan* 
mntchan(void) 
{ 
	Chan *c; 
 
	c = devattach('M', 0); 
	lock(&mntalloc); 
	c->dev = mntalloc.id++; 
	unlock(&mntalloc); 
 
	if(c->mchan) 
		panic("mntchan non-zero %p", c->mchan); 
	return c; 
} 
 
2001/0527    
static Walkqid* 
mntwalk(Chan *c, Chan *nc, char **name, int nname) 
1990/0227    
{ 
2001/0527    
	int i, alloc; 
1990/0227    
	Mnt *m; 
1991/0911    
	Mntrpc *r; 
2001/0527    
	Walkqid *wq; 
2001/0601    
 
2001/0819    
	if(nc != nil) 
		print("mntwalk: nc != nil\n"); 
2001/0527    
	if(nname > MAXWELEM) 
		error("devmnt: too many name elements"); 
	alloc = 0; 
	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); 
	if(waserror()){ 
		if(alloc && wq->clone!=nil) 
			cclose(wq->clone); 
		free(wq); 
		return nil; 
	} 
 
	alloc = 0; 
1991/0911    
	m = mntchk(c); 
2001/0820    
	r = mntralloc(c, m->msize); 
2001/0527    
	if(nc == nil){ 
		nc = devclone(c); 
		/* 
		 * Until the other side accepts this fid, we can't mntclose it. 
		 * Therefore set type to 0 for now; rootclose is known to be safe. 
		 */ 
		nc->type = 0; 
1991/0911    
		alloc = 1; 
1990/0227    
	} 
2001/0527    
	wq->clone = nc; 
 
1992/0824    
	if(waserror()) { 
1991/0911    
		mntfree(r); 
1990/0227    
		nexterror(); 
	} 
2001/0527    
	r->request.type = Twalk; 
1991/0911    
	r->request.fid = c->fid; 
	r->request.newfid = nc->fid; 
2001/0527    
	r->request.nwname = nname; 
	memmove(r->request.wname, name, nname*sizeof(char*)); 
 
1991/0911    
	mountrpc(m, r); 
 
2001/0527    
	if(r->reply.nwqid > nname) 
		error("too many QIDs returned by walk"); 
	if(r->reply.nwqid < nname){ 
		if(alloc) 
			cclose(nc); 
		wq->clone = nil; 
		if(r->reply.nwqid == 0){ 
			free(wq); 
			wq = nil; 
			goto Return; 
		} 
	} 
1991/0911    
 
2001/0527    
	/* move new fid onto mnt device and update its qid */ 
	if(wq->clone != nil){ 
		if(wq->clone != c){ 
			wq->clone->type = c->type; 
2001/0819    
			wq->clone->mchan = c->mchan; 
			incref(c->mchan); 
2001/0527    
		} 
		if(r->reply.nwqid > 0) 
			wq->clone->qid = r->reply.wqid[r->reply.nwqid-1]; 
1990/0227    
	} 
2001/0527    
	wq->nqid = r->reply.nwqid; 
	for(i=0; i<wq->nqid; i++) 
		wq->qid[i] = r->reply.wqid[i]; 
1991/0911    
 
2001/0527    
    Return: 
1990/0227    
	poperror(); 
1991/0911    
	mntfree(r); 
2001/0527    
	poperror(); 
	return wq; 
1990/0227    
} 
 
2001/0527    
static int 
mntstat(Chan *c, uchar *dp, int n) 
1990/0227    
{ 
	Mnt *m; 
1991/0911    
	Mntrpc *r; 
1990/0227    
 
2001/0527    
	if(n < BIT16SZ) 
		error(Eshortstat); 
1991/0911    
	m = mntchk(c); 
2001/0820    
	r = mntralloc(c, m->msize); 
1991/0911    
	if(waserror()) { 
		mntfree(r); 
1990/0227    
		nexterror(); 
	} 
1991/0911    
	r->request.type = Tstat; 
	r->request.fid = c->fid; 
	mountrpc(m, r); 
 
2001/0527    
	if(r->reply.nstat >= 1<<(8*BIT16SZ)) 
		error("returned stat buffer count too large"); 
 
	if(r->reply.nstat > n){ 
		/* doesn't fit; just patch the count and return */ 
		PBIT16((uchar*)dp, r->reply.nstat); 
		n = BIT16SZ; 
	}else{ 
		n = r->reply.nstat; 
		memmove(dp, r->reply.stat, n); 
		validstat(dp, n); 
		mntdirfix(dp, c); 
	} 
1990/0227    
	poperror(); 
1991/0911    
	mntfree(r); 
2001/0527    
	return n; 
1990/0227    
} 
 
1997/0327    
static Chan* 
2001/0527    
mntopencreate(int type, Chan *c, char *name, int omode, ulong perm) 
1990/0227    
{ 
	Mnt *m; 
1991/0911    
	Mntrpc *r; 
1990/0227    
 
1991/0911    
	m = mntchk(c); 
2001/0820    
	r = mntralloc(c, m->msize); 
1991/0911    
	if(waserror()) { 
		mntfree(r); 
1990/0227    
		nexterror(); 
	} 
2001/0527    
	r->request.type = type; 
1991/0911    
	r->request.fid = c->fid; 
	r->request.mode = omode; 
2001/0527    
	if(type == Tcreate){ 
		r->request.perm = perm; 
		r->request.name = name; 
	} 
1991/0911    
	mountrpc(m, r); 
 
	c->qid = r->reply.qid; 
1990/0227    
	c->offset = 0; 
	c->mode = openmode(omode); 
2001/0527    
	c->iounit = r->reply.iounit; 
2001/1206    
	if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ) 
2001/0820    
		c->iounit = m->msize-IOHDRSZ; 
1990/0227    
	c->flag |= COPEN; 
1991/0911    
	poperror(); 
	mntfree(r); 
1993/1015    
 
1993/1016    
	if(c->flag & CCACHE) 
1993/1015    
		copen(c); 
 
1990/0227    
	return c; 
} 
 
2001/0527    
static Chan* 
mntopen(Chan *c, int omode) 
{ 
	return mntopencreate(Topen, c, nil, omode, 0); 
} 
 
1998/0512    
static void 
1990/0227    
mntcreate(Chan *c, char *name, int omode, ulong perm) 
{ 
2001/0527    
	mntopencreate(Tcreate, c, name, omode, perm); 
1990/0227    
} 
 
1998/0512    
static void 
1990/0604    
mntclunk(Chan *c, int t) 
1990/0227    
{ 
	Mnt *m; 
1991/1004    
	Mntrpc *r; 
1998/0512    
 
1991/0911    
	m = mntchk(c); 
2001/0820    
	r = mntralloc(c, m->msize); 
1991/0911    
	if(waserror()){ 
1993/0501    
		mntfree(r); 
1991/1004    
		nexterror(); 
1991/0911    
	} 
1990/0227    
 
1991/0911    
	r->request.type = t; 
	r->request.fid = c->fid; 
	mountrpc(m, r); 
1993/0501    
	mntfree(r); 
1991/1004    
	poperror(); 
} 
 
2001/0527    
void 
2001/0819    
muxclose(Mnt *m) 
1991/1004    
{ 
1993/0321    
	Mntrpc *q, *r; 
1991/1004    
 
1993/0321    
	for(q = m->queue; q; q = r) { 
		r = q->list; 
		mntfree(q); 
	} 
	m->id = 0; 
2001/0820    
	free(m->version); 
	m->version = nil; 
1993/0321    
	mntpntfree(m); 
} 
 
2001/0527    
void 
1992/0320    
mntpntfree(Mnt *m) 
{ 
1992/0620    
	Mnt *f, **l; 
2001/0619    
	Queue *q; 
1992/0620    
 
1992/0320    
	lock(&mntalloc); 
1992/0620    
	l = &mntalloc.list; 
	for(f = *l; f; f = f->list) { 
		if(f == m) { 
			*l = m->list; 
			break; 
		} 
		l = &f->list; 
	} 
1992/0320    
	m->list = mntalloc.mntfree; 
	mntalloc.mntfree = m; 
2001/0619    
	q = m->q; 
1992/0320    
	unlock(&mntalloc); 
2001/0619    
 
	qfree(q); 
1990/0227    
} 
 
1997/0327    
static void 
1990/0604    
mntclose(Chan *c) 
{ 
	mntclunk(c, Tclunk); 
} 
 
1998/0512    
static void 
1991/0911    
mntremove(Chan *c) 
1990/0227    
{ 
1991/0911    
	mntclunk(c, Tremove); 
} 
 
2001/0527    
static int 
mntwstat(Chan *c, uchar *dp, int n) 
1991/0911    
{ 
1990/0227    
	Mnt *m; 
1991/0911    
	Mntrpc *r; 
1990/0227    
 
1991/0911    
	m = mntchk(c); 
2001/0820    
	r = mntralloc(c, m->msize); 
1991/0911    
	if(waserror()) { 
		mntfree(r); 
1990/0227    
		nexterror(); 
	} 
1991/0911    
	r->request.type = Twstat; 
	r->request.fid = c->fid; 
2001/0527    
	r->request.nstat = n; 
	r->request.stat = dp; 
1991/0911    
	mountrpc(m, r); 
1990/0227    
	poperror(); 
1991/0911    
	mntfree(r); 
2001/0527    
	return n; 
1990/0227    
} 
 
1998/0512    
static long 
1998/0319    
mntread(Chan *c, void *buf, long n, vlong off) 
1990/0227    
{ 
1991/0911    
	uchar *p, *e; 
2001/0527    
	int nc, cache, isdir, dirlen; 
1990/0227    
 
1995/0204    
	isdir = 0; 
	cache = c->flag & CCACHE; 
2001/0527    
	if(c->qid.type & QTDIR) { 
1995/0204    
		cache = 0; 
		isdir = 1; 
	} 
 
1995/0129    
	p = buf; 
1995/0204    
	if(cache) { 
1998/0327    
		nc = cread(c, buf, n, off); 
1993/1015    
		if(nc > 0) { 
1993/1102    
			n -= nc; 
			if(n == 0) 
				return nc; 
1995/0129    
			p += nc; 
1998/0327    
			off += nc; 
1993/1015    
		} 
1998/0327    
		n = mntrdwr(Tread, c, p, n, off); 
		cupdate(c, p, n, off); 
1995/0129    
		return n + nc; 
1993/1014    
	} 
 
1998/0327    
	n = mntrdwr(Tread, c, buf, n, off); 
1995/0204    
	if(isdir) { 
2001/0527    
		for(e = &p[n]; p+BIT16SZ < e; p += dirlen){ 
			dirlen = BIT16SZ+GBIT16(p); 
			if(p+dirlen > e) 
				break; 
			validstat(p, dirlen); 
1995/0204    
			mntdirfix(p, c); 
2001/0527    
		} 
		if(p != e) 
			error(Esbadstat); 
1995/0204    
	} 
1990/0227    
	return n; 
} 
 
1998/0512    
static long 
1998/0319    
mntwrite(Chan *c, void *buf, long n, vlong off) 
1990/0227    
{ 
1998/0327    
	return mntrdwr(Twrite, c, buf, n, off); 
1995/0108    
} 
 
2001/0527    
long 
1998/0327    
mntrdwr(int type, Chan *c, void *buf, long n, vlong off) 
1995/0129    
{ 
	Mnt *m; 
1993/1016    
 	Mntrpc *r; 
1991/0911    
	char *uba; 
1993/1015    
	int cache; 
1998/0908    
	ulong cnt, nr, nreq; 
1990/0227    
 
1993/1016    
	m = mntchk(c); 
1991/0911    
	uba = buf; 
1993/0907    
	cnt = 0; 
1993/1016    
	cache = c->flag & CCACHE; 
2001/0527    
	if(c->qid.type & QTDIR) 
1995/0204    
		cache = 0; 
1993/0907    
	for(;;) { 
2001/0820    
		r = mntralloc(c, m->msize); 
1991/0911    
		if(waserror()) { 
			mntfree(r); 
			nexterror(); 
		} 
		r->request.type = type; 
		r->request.fid = c->fid; 
1998/0327    
		r->request.offset = off; 
1991/0911    
		r->request.data = uba; 
2001/0527    
		nr = n; 
2001/0820    
		if(nr > m->msize-IOHDRSZ) 
			nr = m->msize-IOHDRSZ; 
2001/0527    
		r->request.count = nr; 
1991/0911    
		mountrpc(m, r); 
1998/0908    
		nreq = r->request.count; 
1991/0911    
		nr = r->reply.count; 
1998/0908    
		if(nr > nreq) 
			nr = nreq; 
1993/1015    
 
1991/0911    
		if(type == Tread) 
2001/0619    
			r->b = bl2mem((uchar*)uba, r->b, nr); 
1993/1015    
		else if(cache) 
1998/0327    
			cwrite(c, (uchar*)uba, nr, off); 
1993/1015    
 
1991/0911    
		poperror(); 
		mntfree(r); 
1998/0327    
		off += nr; 
1991/0911    
		uba += nr; 
		cnt += nr; 
1993/0907    
		n -= nr; 
1998/0908    
		if(nr != nreq || n == 0 || up->nnote) 
1991/0911    
			break; 
1990/0227    
	} 
1991/0911    
	return cnt; 
1990/0227    
} 
 
2001/0527    
void 
1991/0911    
mountrpc(Mnt *m, Mntrpc *r) 
1990/0604    
{ 
2001/0503    
	char *sn, *cn; 
1993/0501    
	int t; 
 
	r->reply.tag = 0; 
2000/0102    
	r->reply.type = Tmax;	/* can't ever be a valid message type */ 
1992/0620    
 
1991/0911    
	mountio(m, r); 
1992/0620    
 
1993/0501    
	t = r->reply.type; 
	switch(t) { 
	case Rerror: 
		error(r->reply.ename); 
	case Rflush: 
1992/0111    
		error(Eintr); 
1993/0501    
	default: 
		if(t == r->request.type+1) 
			break; 
2001/0503    
		sn = "?"; 
		if(m->c->name != nil) 
			sn = m->c->name->s; 
		cn = "?"; 
		if(r->c != nil && r->c->name != nil) 
			cn = r->c->name->s; 
		print("mnt: proc %s %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n", 
			up->text, up->pid, sn, cn, 
			r, r->request.tag, r->request.fid, r->request.type, 
			r->reply.type, r->reply.tag); 
1992/0113    
		error(Emountrpc); 
1990/1123    
	} 
} 
 
2001/0527    
void 
1991/0911    
mountio(Mnt *m, Mntrpc *r) 
1990/1123    
{ 
1991/0911    
	int n; 
1990/1124    
 
2000/0105    
	while(waserror()) { 
		if(m->rip == up) 
			mntgate(m); 
2001/0924    
		if(strcmp(up->errstr, Eintr) != 0){ 
2000/0105    
			mntflushfree(m, r); 
			nexterror(); 
		} 
2001/0820    
		r = mntflushalloc(r, m->msize); 
2000/0105    
	} 
 
1991/0911    
	lock(m); 
	r->m = m; 
	r->list = m->queue; 
	m->queue = r; 
	unlock(m); 
 
	/* Transmit a file system rpc */ 
2001/0820    
	if(m->msize == 0) 
		panic("msize"); 
	n = convS2M(&r->request, r->rpc, m->msize); 
1997/0327    
	if(n < 0) 
		panic("bad message type in mountio"); 
2001/0527    
	if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n) 
		error(Emountrpc); 
2000/0104    
	r->stime = fastticks(nil); 
	r->reqlen = n; 
1990/1124    
 
1991/0911    
	/* Gate readers onto the mount point one at a time */ 
	for(;;) { 
		lock(m); 
		if(m->rip == 0) 
			break; 
		unlock(m); 
		sleep(&r->r, rpcattn, r); 
2000/0104    
		if(r->done){ 
			poperror(); 
2000/0105    
			mntflushfree(m, r); 
1991/0911    
			return; 
2000/0104    
		} 
1990/1124    
	} 
1993/0501    
	m->rip = up; 
1991/0911    
	unlock(m); 
	while(r->done == 0) { 
2001/0527    
		if(mntrpcread(m, r) < 0) 
			error(Emountrpc); 
1991/0911    
		mountmux(m, r); 
	} 
	mntgate(m); 
2000/0104    
	poperror(); 
2000/0105    
	mntflushfree(m, r); 
1990/1124    
} 
 
2001/0527    
int 
1991/0911    
mntrpcread(Mnt *m, Mntrpc *r) 
1990/1124    
{ 
2001/0619    
	int i, t, len, hlen; 
	Block *b, **l, *nb; 
1992/0505    
 
2001/0527    
	r->reply.type = 0; 
	r->reply.tag = 0; 
2001/0619    
 
	/* read at least length, type, and tag and pullup to a single block */ 
	while(qlen(m->q) < BIT32SZ+BIT8SZ+BIT16SZ){ 
2002/0615    
		b = devtab[m->c->type]->bread(m->c, m->msize, 0); 
2001/0619    
		if(b == nil) 
			return -1; 
2001/0825    
		qaddlist(m->q, b); 
2001/0527    
	} 
2001/0619    
	nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ); 
	len = GBIT32(nb->rp); 
 
	/* read in the rest of the message */ 
	while(qlen(m->q) < len){ 
2002/0615    
		b = devtab[m->c->type]->bread(m->c, m->msize, 0); 
2001/0619    
		if(b == nil) 
			return -1; 
2001/0825    
		qaddlist(m->q, b); 
2001/0527    
	} 
2001/0619    
 
	/* pullup the header (i.e. everything except data) */ 
	t = nb->rp[BIT32SZ]; 
	switch(t){ 
	case Rread: 
		hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ; 
		break; 
	default: 
		hlen = len; 
		break; 
2001/0527    
	} 
2001/0619    
	nb = pullupqueue(m->q, hlen); 
1992/0503    
 
2001/0619    
	if(convM2S(nb->rp, len, &r->reply) <= 0){ 
		/* bad message, dump it */ 
		print("mntrpcread: convM2S failed\n"); 
		qdiscard(m->q, len); 
2001/0527    
		return -1; 
1991/0911    
	} 
2001/0619    
 
	/* hang the data off of the fcall struct */ 
	l = &r->b; 
	*l = nil; 
	do { 
		b = qremove(m->q); 
		if(hlen > 0){ 
			b->rp += hlen; 
			len -= hlen; 
			hlen = 0; 
		} 
		i = BLEN(b); 
		if(i <= len){ 
			len -= i; 
			*l = b; 
			l = &(b->next); 
		} else { 
			/* split block and put unused bit back */ 
			nb = allocb(i-len); 
			memmove(nb->wp, b->rp+len, i-len); 
			b->wp = b->rp+len; 
			nb->wp += i-len; 
			qputback(m->q, nb); 
			*l = b; 
			return 0; 
		} 
	}while(len > 0); 
 
2001/0527    
	return 0; 
1990/0604    
} 
1990/11211    
 
2001/0527    
void 
1991/0911    
mntgate(Mnt *m) 
1990/0717    
{ 
1991/0911    
	Mntrpc *q; 
 
	lock(m); 
	m->rip = 0; 
1993/0501    
	for(q = m->queue; q; q = q->list) { 
1997/0220    
		if(q->done == 0) 
		if(wakeup(&q->r)) 
			break; 
1993/0501    
	} 
1991/0911    
	unlock(m); 
1990/0717    
} 
1990/11211    
 
2001/0527    
void 
1991/0911    
mountmux(Mnt *m, Mntrpc *r) 
1990/0227    
{ 
1992/0825    
	Mntrpc **l, *q; 
1990/0227    
 
1991/0911    
	lock(m); 
	l = &m->queue; 
	for(q = *l; q; q = q->list) { 
2000/0105    
		/* look for a reply to a message */ 
2000/0104    
		if(q->request.tag == r->reply.tag) { 
1991/0911    
			*l = q->list; 
1999/0212    
			if(q != r) { 
				/* 
				 * Completed someone else. 
				 * Trade pointers to receive buffer. 
				 */ 
1993/0501    
				q->reply = r->reply; 
2001/0619    
				q->b = r->b; 
				r->b = nil; 
1998/0916    
			} 
2000/0102    
			q->done = 1; 
			unlock(m); 
2000/0101    
			if(mntstats != nil) 
				(*mntstats)(q->request.type, 
					m->c, q->stime, 
					q->reqlen + r->replen); 
			if(q != r) 
				wakeup(&q->r); 
1991/0911    
			return; 
		} 
		l = &q->list; 
1990/0227    
	} 
1991/0911    
	unlock(m); 
2001/0527    
	print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type); 
1991/0911    
} 
1990/0227    
 
2000/0105    
/* 
 * Create a new flush request and chain the previous 
 * requests from it 
 */ 
2001/0527    
Mntrpc* 
mntflushalloc(Mntrpc *r, ulong iounit) 
1991/0911    
{ 
2000/0104    
	Mntrpc *fr; 
1990/0511    
 
2001/0527    
	fr = mntralloc(0, iounit); 
1990/0511    
 
2000/0104    
	fr->request.type = Tflush; 
	if(r->request.type == Tflush) 
		fr->request.oldtag = r->request.oldtag; 
	else 
		fr->request.oldtag = r->request.tag; 
2000/0105    
	fr->flushed = r; 
1991/0911    
 
2000/0105    
	return fr; 
} 
2000/0104    
 
2000/0105    
/* 
 *  Free a chain of flushes.  Remove each unanswered 
 *  flush and the original message from the unanswered 
 *  request queue.  Mark the original message as done 
 *  and if it hasn't been answered set the reply to to 
 *  Rflush. 
 */ 
2001/0527    
void 
2000/0105    
mntflushfree(Mnt *m, Mntrpc *r) 
{ 
	Mntrpc *fr; 
 
	while(r){ 
		fr = r->flushed; 
		if(!r->done){ 
			r->reply.type = Rflush; 
			mntqrm(m, r); 
		} 
		if(fr) 
			mntfree(r); 
		r = fr; 
1990/03081    
	} 
1991/0911    
} 
1991/0901    
 
2001/0527    
Mntrpc* 
2001/0820    
mntralloc(Chan *c, ulong msize) 
1991/0911    
{ 
	Mntrpc *new; 
1991/0901    
 
1992/0620    
	lock(&mntalloc); 
	new = mntalloc.rpcfree; 
1999/0212    
	if(new == nil){ 
		new = malloc(sizeof(Mntrpc)); 
		if(new == nil) { 
1991/0911    
			unlock(&mntalloc); 
1999/0212    
			exhausted("mount rpc header"); 
		} 
		/* 
		 * The header is split from the data buffer as 
		 * mountmux may swap the buffer with another header. 
		 */ 
2001/0820    
		new->rpc = mallocz(msize, 0); 
1999/0212    
		if(new->rpc == nil){ 
			free(new); 
			unlock(&mntalloc); 
1992/0620    
			exhausted("mount rpc buffer"); 
1991/0911    
		} 
2001/0820    
		new->rpclen = msize; 
1992/0620    
		new->request.tag = mntalloc.rpctag++; 
1991/0904    
	} 
1999/0212    
	else { 
		mntalloc.rpcfree = new->list; 
		mntalloc.nrpcfree--; 
2001/0820    
		if(new->rpclen < msize){ 
2001/0819    
			free(new->rpc); 
2001/0820    
			new->rpc = mallocz(msize, 0); 
2001/0819    
			if(new->rpc == nil){ 
				free(new); 
				mntalloc.nrpcused--; 
				unlock(&mntalloc); 
				exhausted("mount rpc buffer"); 
			} 
2001/0820    
			new->rpclen = msize; 
2001/0819    
		} 
1999/0212    
	} 
	mntalloc.nrpcused++; 
1992/0620    
	unlock(&mntalloc); 
1993/0501    
	new->c = c; 
1992/0620    
	new->done = 0; 
2000/0105    
	new->flushed = nil; 
2001/0619    
	new->b = nil; 
1992/0620    
	return new; 
1991/0911    
} 
 
2001/0527    
void 
1991/0911    
mntfree(Mntrpc *r) 
{ 
2001/0619    
	if(r->b != nil) 
		freeblist(r->b); 
1991/0911    
	lock(&mntalloc); 
1999/0212    
	if(mntalloc.nrpcfree >= 10){ 
		free(r->rpc); 
		free(r); 
	} 
	else{ 
		r->list = mntalloc.rpcfree; 
		mntalloc.rpcfree = r; 
		mntalloc.nrpcfree++; 
	} 
	mntalloc.nrpcused--; 
1991/0911    
	unlock(&mntalloc); 
} 
 
2001/0527    
void 
1991/0911    
mntqrm(Mnt *m, Mntrpc *r) 
{ 
	Mntrpc **l, *f; 
 
	lock(m); 
	r->done = 1; 
 
	l = &m->queue; 
	for(f = *l; f; f = f->list) { 
		if(f == r) { 
			*l = r->list; 
			break; 
1990/0703    
		} 
1991/0911    
		l = &f->list; 
1990/0227    
	} 
1991/0911    
	unlock(m); 
} 
1990/0227    
 
2001/0527    
Mnt* 
1991/0911    
mntchk(Chan *c) 
{ 
	Mnt *m; 
 
2001/0819    
	/* This routine is mostly vestiges of prior lives; now it's just sanity checking */ 
1993/0501    
 
2001/0819    
	if(c->mchan == nil) 
		panic("mntchk 1: nil mchan c %s\n", c2name(c)); 
 
	m = c->mchan->mux; 
 
	if(m == nil) 
		print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan)); 
 
1993/0501    
	/* 
2001/0819    
	 * Was it closed and reused (was error(Eshutdown); now, it can't happen) 
1993/0501    
	 */ 
	if(m->id == 0 || m->id >= c->dev) 
2001/0819    
		panic("mntchk 3: can't happen"); 
1993/0501    
 
1991/0911    
	return m; 
1990/0717    
} 
 
2001/0527    
/* 
 * Rewrite channel type and dev for in-flight data to 
 * reflect local values.  These entries are known to be 
 * the first two in the Dir encoding after the count. 
 */ 
void 
1991/0911    
mntdirfix(uchar *dirbuf, Chan *c) 
{ 
2001/0527    
	uint r; 
1997/0408    
 
	r = devtab[c->type]->dc; 
2001/0527    
	dirbuf += BIT16SZ;	/* skip count */ 
	PBIT16(dirbuf, r); 
	dirbuf += BIT16SZ; 
	PBIT32(dirbuf, c->dev); 
1991/0911    
} 
 
2001/0527    
int 
1999/0320    
rpcattn(void *v) 
1991/0911    
{ 
1999/0320    
	Mntrpc *r; 
 
	r = v; 
1991/0911    
	return r->done || r->m->rip == 0; 
} 
1997/0327    
 
Dev mntdevtab = { 
1997/0409    
	'M', 
1997/0408    
	"mnt", 
 
1997/0327    
	mntreset, 
	devinit, 
2002/0109    
	devshutdown, 
1997/0327    
	mntattach, 
	mntwalk, 
	mntstat, 
	mntopen, 
	mntcreate, 
	mntclose, 
	mntread, 
	devbread, 
	mntwrite, 
	devbwrite, 
	mntremove, 
	mntwstat, 
}; 


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