xref: /plan9-contrib/sys/src/9k/port/devmnt.c (revision 3ecb170494564f799a25abf22ce61bc710c24213)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier /*
99ef1f84bSDavid du Colombier  * References are managed as follows:
109ef1f84bSDavid du Colombier  * The channel to the server - a network connection or pipe - has one
119ef1f84bSDavid du Colombier  * reference for every Chan open on the server.  The server channel has
129ef1f84bSDavid du Colombier  * c->mux set to the Mnt used for muxing control to that server.  Mnts
139ef1f84bSDavid du Colombier  * have no reference count; they go away when c goes away.
149ef1f84bSDavid du Colombier  * Each channel derived from the mount point has mchan set to c,
159ef1f84bSDavid du Colombier  * and increfs/decrefs mchan to manage references on the server
169ef1f84bSDavid du Colombier  * connection.
179ef1f84bSDavid du Colombier  */
189ef1f84bSDavid du Colombier 
19*3ecb1704SDavid du Colombier #define MAXRPC (IOHDRSZ+16*1024)	/* maybe a larger size will be faster */
20*3ecb1704SDavid du Colombier /* use a known-good common size for initial negotiation */
21*3ecb1704SDavid du Colombier #define MAXCMNRPC (IOHDRSZ+8192)
229ef1f84bSDavid du Colombier 
239ef1f84bSDavid du Colombier struct Mntrpc
249ef1f84bSDavid du Colombier {
259ef1f84bSDavid du Colombier 	Chan*	c;		/* Channel for whom we are working */
269ef1f84bSDavid du Colombier 	Mntrpc*	list;		/* Free/pending list */
279ef1f84bSDavid du Colombier 	Fcall	request;	/* Outgoing file system protocol message */
289ef1f84bSDavid du Colombier 	Fcall 	reply;		/* Incoming reply */
299ef1f84bSDavid du Colombier 	Mnt*	m;		/* Mount device during rpc */
309ef1f84bSDavid du Colombier 	Rendez	r;		/* Place to hang out */
319ef1f84bSDavid du Colombier 	uchar*	rpc;		/* I/O Data buffer */
329ef1f84bSDavid du Colombier 	uint	rpclen;		/* len of buffer */
339ef1f84bSDavid du Colombier 	Block	*b;		/* reply blocks */
349ef1f84bSDavid du Colombier 	char	done;		/* Rpc completed */
359ef1f84bSDavid du Colombier 	uvlong	stime;		/* start time for mnt statistics */
369ef1f84bSDavid du Colombier 	ulong	reqlen;		/* request length for mnt statistics */
379ef1f84bSDavid du Colombier 	ulong	replen;		/* reply length for mnt statistics */
389ef1f84bSDavid du Colombier 	Mntrpc*	flushed;	/* message this one flushes */
399ef1f84bSDavid du Colombier };
409ef1f84bSDavid du Colombier 
419ef1f84bSDavid du Colombier enum
429ef1f84bSDavid du Colombier {
439ef1f84bSDavid du Colombier 	TAGSHIFT = 5,			/* ulong has to be 32 bits */
449ef1f84bSDavid du Colombier 	TAGMASK = (1<<TAGSHIFT)-1,
459ef1f84bSDavid du Colombier 	NMASK = (64*1024)>>TAGSHIFT,
469ef1f84bSDavid du Colombier };
479ef1f84bSDavid du Colombier 
489ef1f84bSDavid du Colombier struct Mntalloc
499ef1f84bSDavid du Colombier {
509ef1f84bSDavid du Colombier 	Lock;
519ef1f84bSDavid du Colombier 	Mnt*	list;		/* Mount devices in use */
529ef1f84bSDavid du Colombier 	Mnt*	mntfree;	/* Free list */
539ef1f84bSDavid du Colombier 	Mntrpc*	rpcfree;
549ef1f84bSDavid du Colombier 	int	nrpcfree;
559ef1f84bSDavid du Colombier 	int	nrpcused;
569ef1f84bSDavid du Colombier 	uint	id;
579ef1f84bSDavid du Colombier 	ulong	tagmask[NMASK];
589ef1f84bSDavid du Colombier }mntalloc;
599ef1f84bSDavid du Colombier 
609ef1f84bSDavid du Colombier Mnt*	mntchk(Chan*);
619ef1f84bSDavid du Colombier void	mntdirfix(uchar*, Chan*);
629ef1f84bSDavid du Colombier Mntrpc*	mntflushalloc(Mntrpc*, ulong);
639ef1f84bSDavid du Colombier void	mntflushfree(Mnt*, Mntrpc*);
649ef1f84bSDavid du Colombier void	mntfree(Mntrpc*);
659ef1f84bSDavid du Colombier void	mntgate(Mnt*);
669ef1f84bSDavid du Colombier void	mntpntfree(Mnt*);
679ef1f84bSDavid du Colombier void	mntqrm(Mnt*, Mntrpc*);
689ef1f84bSDavid du Colombier Mntrpc*	mntralloc(Chan*, ulong);
699ef1f84bSDavid du Colombier long	mntrdwr(int, Chan*, void*, long, vlong);
709ef1f84bSDavid du Colombier int	mntrpcread(Mnt*, Mntrpc*);
719ef1f84bSDavid du Colombier void	mountio(Mnt*, Mntrpc*);
729ef1f84bSDavid du Colombier void	mountmux(Mnt*, Mntrpc*);
739ef1f84bSDavid du Colombier void	mountrpc(Mnt*, Mntrpc*);
749ef1f84bSDavid du Colombier int	rpcattn(void*);
759ef1f84bSDavid du Colombier Chan*	mntchan(void);
769ef1f84bSDavid du Colombier 
779ef1f84bSDavid du Colombier char	Esbadstat[] = "invalid directory entry received from server";
789ef1f84bSDavid du Colombier char	Enoversion[] = "version not established for mount channel";
799ef1f84bSDavid du Colombier 
809ef1f84bSDavid du Colombier 
819ef1f84bSDavid du Colombier void (*mntstats)(int, Chan*, uvlong, ulong);
829ef1f84bSDavid du Colombier 
839ef1f84bSDavid du Colombier static void
mntreset(void)849ef1f84bSDavid du Colombier mntreset(void)
859ef1f84bSDavid du Colombier {
869ef1f84bSDavid du Colombier 	mntalloc.id = 1;
879ef1f84bSDavid du Colombier 	mntalloc.tagmask[0] = 1;			/* don't allow 0 as a tag */
889ef1f84bSDavid du Colombier 	mntalloc.tagmask[NMASK-1] = 0x80000000UL;	/* don't allow NOTAG */
899ef1f84bSDavid du Colombier 	fmtinstall('F', fcallfmt);
909ef1f84bSDavid du Colombier 	fmtinstall('D', dirfmt);
919ef1f84bSDavid du Colombier /* We can't install %M since eipfmt does and is used in the kernel [sape] */
929ef1f84bSDavid du Colombier 
939ef1f84bSDavid du Colombier 	cinit();
949ef1f84bSDavid du Colombier }
959ef1f84bSDavid du Colombier 
969ef1f84bSDavid du Colombier /*
979ef1f84bSDavid du Colombier  * Version is not multiplexed: message sent only once per connection.
989ef1f84bSDavid du Colombier  */
999ef1f84bSDavid du Colombier usize
mntversion(Chan * c,u32int msize,char * version,usize returnlen)1009ef1f84bSDavid du Colombier mntversion(Chan *c, u32int msize, char *version, usize returnlen)
1019ef1f84bSDavid du Colombier {
1029ef1f84bSDavid du Colombier 	Fcall f;
1039ef1f84bSDavid du Colombier 	uchar *msg;
1049ef1f84bSDavid du Colombier 	Mnt *mnt;
1059ef1f84bSDavid du Colombier 	char *v;
1069ef1f84bSDavid du Colombier 	long l, n;
1079ef1f84bSDavid du Colombier 	usize k;
1089ef1f84bSDavid du Colombier 	vlong oo;
1099ef1f84bSDavid du Colombier 	char buf[128];
1109ef1f84bSDavid du Colombier 
1119ef1f84bSDavid du Colombier 	qlock(&c->umqlock);	/* make sure no one else does this until we've established ourselves */
1129ef1f84bSDavid du Colombier 	if(waserror()){
1139ef1f84bSDavid du Colombier 		qunlock(&c->umqlock);
1149ef1f84bSDavid du Colombier 		nexterror();
1159ef1f84bSDavid du Colombier 	}
1169ef1f84bSDavid du Colombier 
1179ef1f84bSDavid du Colombier 	/* defaults */
1189ef1f84bSDavid du Colombier 	if(msize == 0)
1199ef1f84bSDavid du Colombier 		msize = MAXRPC;
1209ef1f84bSDavid du Colombier 	if(msize > c->iounit && c->iounit != 0)
1219ef1f84bSDavid du Colombier 		msize = c->iounit;
1229ef1f84bSDavid du Colombier 	v = version;
1239ef1f84bSDavid du Colombier 	if(v == nil || v[0] == '\0')
1249ef1f84bSDavid du Colombier 		v = VERSION9P;
1259ef1f84bSDavid du Colombier 
1269ef1f84bSDavid du Colombier 	///* validity */
1279ef1f84bSDavid du Colombier 	//if(msize < 0)	pointless if msize unsigned, but but should it be?
1289ef1f84bSDavid du Colombier 	//	error("bad iounit in version call");
1299ef1f84bSDavid du Colombier 	if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
1309ef1f84bSDavid du Colombier 		error("bad 9P version specification");
1319ef1f84bSDavid du Colombier 
1329ef1f84bSDavid du Colombier 	mnt = c->mux;
1339ef1f84bSDavid du Colombier 
1349ef1f84bSDavid du Colombier 	if(mnt != nil){
1359ef1f84bSDavid du Colombier 		qunlock(&c->umqlock);
1369ef1f84bSDavid du Colombier 		poperror();
1379ef1f84bSDavid du Colombier 
1389ef1f84bSDavid du Colombier 		strecpy(buf, buf+sizeof buf, mnt->version);
1399ef1f84bSDavid du Colombier 		k = strlen(buf);
1409ef1f84bSDavid du Colombier 		if(strncmp(buf, v, k) != 0){
1419ef1f84bSDavid du Colombier 			snprint(buf, sizeof buf, "incompatible 9P versions %s %s", mnt->version, v);
1429ef1f84bSDavid du Colombier 			error(buf);
1439ef1f84bSDavid du Colombier 		}
1449ef1f84bSDavid du Colombier 		if(returnlen != 0){
1459ef1f84bSDavid du Colombier 			if(returnlen < k)
1469ef1f84bSDavid du Colombier 				error(Eshort);
1479ef1f84bSDavid du Colombier 			memmove(version, buf, k);
1489ef1f84bSDavid du Colombier 		}
1499ef1f84bSDavid du Colombier 		return k;
1509ef1f84bSDavid du Colombier 	}
1519ef1f84bSDavid du Colombier 
1529ef1f84bSDavid du Colombier 	f.type = Tversion;
1539ef1f84bSDavid du Colombier 	f.tag = NOTAG;
1549ef1f84bSDavid du Colombier 	f.msize = msize;
1559ef1f84bSDavid du Colombier 	f.version = v;
156*3ecb1704SDavid du Colombier 	msg = malloc(MAXCMNRPC);
1579ef1f84bSDavid du Colombier 	if(msg == nil)
1589ef1f84bSDavid du Colombier 		exhausted("version memory");
1599ef1f84bSDavid du Colombier 	if(waserror()){
1609ef1f84bSDavid du Colombier 		free(msg);
1619ef1f84bSDavid du Colombier 		nexterror();
1629ef1f84bSDavid du Colombier 	}
163*3ecb1704SDavid du Colombier 	k = convS2M(&f, msg, MAXCMNRPC);
1649ef1f84bSDavid du Colombier 	if(k == 0)
1659ef1f84bSDavid du Colombier 		error("bad fversion conversion on send");
1669ef1f84bSDavid du Colombier 
1679ef1f84bSDavid du Colombier 	lock(c);
1689ef1f84bSDavid du Colombier 	oo = c->offset;
1699ef1f84bSDavid du Colombier 	c->offset += k;
1709ef1f84bSDavid du Colombier 	unlock(c);
1719ef1f84bSDavid du Colombier 
1729ef1f84bSDavid du Colombier 	l = c->dev->write(c, msg, k, oo);
1739ef1f84bSDavid du Colombier 
1749ef1f84bSDavid du Colombier 	if(l < k){
1759ef1f84bSDavid du Colombier 		lock(c);
1769ef1f84bSDavid du Colombier 		c->offset -= k - l;
1779ef1f84bSDavid du Colombier 		unlock(c);
1789ef1f84bSDavid du Colombier 		error("short write in fversion");
1799ef1f84bSDavid du Colombier 	}
1809ef1f84bSDavid du Colombier 
1819ef1f84bSDavid du Colombier 	/* message sent; receive and decode reply */
182*3ecb1704SDavid du Colombier 	n = c->dev->read(c, msg, MAXCMNRPC, c->offset);
1839ef1f84bSDavid du Colombier 	if(n <= 0)
1849ef1f84bSDavid du Colombier 		error("EOF receiving fversion reply");
1859ef1f84bSDavid du Colombier 
1869ef1f84bSDavid du Colombier 	lock(c);
1879ef1f84bSDavid du Colombier 	c->offset += n;
1889ef1f84bSDavid du Colombier 	unlock(c);
1899ef1f84bSDavid du Colombier 
1909ef1f84bSDavid du Colombier 	l = convM2S(msg, n, &f);
1919ef1f84bSDavid du Colombier 	if(l != n)
1929ef1f84bSDavid du Colombier 		error("bad fversion conversion on reply");
1939ef1f84bSDavid du Colombier 	if(f.type != Rversion){
1949ef1f84bSDavid du Colombier 		if(f.type == Rerror)
1959ef1f84bSDavid du Colombier 			error(f.ename);
1969ef1f84bSDavid du Colombier 		error("unexpected reply type in fversion");
1979ef1f84bSDavid du Colombier 	}
1989ef1f84bSDavid du Colombier 	if(f.msize > msize)
1999ef1f84bSDavid du Colombier 		error("server tries to increase msize in fversion");
2009ef1f84bSDavid du Colombier 	if(f.msize<256 || f.msize>1024*1024)
2019ef1f84bSDavid du Colombier 		error("nonsense value of msize in fversion");
2029ef1f84bSDavid du Colombier 	k = strlen(f.version);
2039ef1f84bSDavid du Colombier 	if(strncmp(f.version, v, k) != 0)
2049ef1f84bSDavid du Colombier 		error("bad 9P version returned from server");
2059ef1f84bSDavid du Colombier 
2069ef1f84bSDavid du Colombier 	/* now build Mnt associated with this connection */
2079ef1f84bSDavid du Colombier 	lock(&mntalloc);
2089ef1f84bSDavid du Colombier 	mnt = mntalloc.mntfree;
2099ef1f84bSDavid du Colombier 	if(mnt != nil)
2109ef1f84bSDavid du Colombier 		mntalloc.mntfree = mnt->list;
2119ef1f84bSDavid du Colombier 	else {
2129ef1f84bSDavid du Colombier 		mnt = malloc(sizeof(Mnt));
2139ef1f84bSDavid du Colombier 		if(mnt == nil) {
2149ef1f84bSDavid du Colombier 			unlock(&mntalloc);
2159ef1f84bSDavid du Colombier 			exhausted("mount devices");
2169ef1f84bSDavid du Colombier 		}
2179ef1f84bSDavid du Colombier 	}
2189ef1f84bSDavid du Colombier 	mnt->list = mntalloc.list;
2199ef1f84bSDavid du Colombier 	mntalloc.list = mnt;
2209ef1f84bSDavid du Colombier 	mnt->version = nil;
2219ef1f84bSDavid du Colombier 	kstrdup(&mnt->version, f.version);
2229ef1f84bSDavid du Colombier 	mnt->id = mntalloc.id++;
2239ef1f84bSDavid du Colombier 	mnt->q = qopen(10*MAXRPC, 0, nil, nil);
2249ef1f84bSDavid du Colombier 	mnt->msize = f.msize;
2259ef1f84bSDavid du Colombier 	unlock(&mntalloc);
2269ef1f84bSDavid du Colombier 
2279ef1f84bSDavid du Colombier 	if(returnlen != 0){
2289ef1f84bSDavid du Colombier 		if(returnlen < k)
2299ef1f84bSDavid du Colombier 			error(Eshort);
2309ef1f84bSDavid du Colombier 		memmove(version, f.version, k);
2319ef1f84bSDavid du Colombier 	}
2329ef1f84bSDavid du Colombier 
2339ef1f84bSDavid du Colombier 	poperror();	/* msg */
2349ef1f84bSDavid du Colombier 	free(msg);
2359ef1f84bSDavid du Colombier 
2369ef1f84bSDavid du Colombier 	lock(mnt);
2379ef1f84bSDavid du Colombier 	mnt->queue = 0;
2389ef1f84bSDavid du Colombier 	mnt->rip = 0;
2399ef1f84bSDavid du Colombier 
2409ef1f84bSDavid du Colombier 	c->flag |= CMSG;
2419ef1f84bSDavid du Colombier 	c->mux = mnt;
2429ef1f84bSDavid du Colombier 	mnt->c = c;
2439ef1f84bSDavid du Colombier 	unlock(mnt);
2449ef1f84bSDavid du Colombier 
2459ef1f84bSDavid du Colombier 	poperror();	/* c */
2469ef1f84bSDavid du Colombier 	qunlock(&c->umqlock);
2479ef1f84bSDavid du Colombier 
2489ef1f84bSDavid du Colombier 	return k;
2499ef1f84bSDavid du Colombier }
2509ef1f84bSDavid du Colombier 
2519ef1f84bSDavid du Colombier Chan*
mntauth(Chan * c,char * spec)2529ef1f84bSDavid du Colombier mntauth(Chan *c, char *spec)
2539ef1f84bSDavid du Colombier {
2549ef1f84bSDavid du Colombier 	Mnt *mnt;
2559ef1f84bSDavid du Colombier 	Mntrpc *r;
2569ef1f84bSDavid du Colombier 
2579ef1f84bSDavid du Colombier 	mnt = c->mux;
2589ef1f84bSDavid du Colombier 
2599ef1f84bSDavid du Colombier 	if(mnt == nil){
2609ef1f84bSDavid du Colombier 		mntversion(c, MAXRPC, VERSION9P, 0);
2619ef1f84bSDavid du Colombier 		mnt = c->mux;
2629ef1f84bSDavid du Colombier 		if(mnt == nil)
2639ef1f84bSDavid du Colombier 			error(Enoversion);
2649ef1f84bSDavid du Colombier 	}
2659ef1f84bSDavid du Colombier 
2669ef1f84bSDavid du Colombier 	c = mntchan();
2679ef1f84bSDavid du Colombier 	if(waserror()) {
2689ef1f84bSDavid du Colombier 		/* Close must not be called since it will
2699ef1f84bSDavid du Colombier 		 * call mnt recursively
2709ef1f84bSDavid du Colombier 		 */
2719ef1f84bSDavid du Colombier 		chanfree(c);
2729ef1f84bSDavid du Colombier 		nexterror();
2739ef1f84bSDavid du Colombier 	}
2749ef1f84bSDavid du Colombier 
2759ef1f84bSDavid du Colombier 	r = mntralloc(0, mnt->msize);
2769ef1f84bSDavid du Colombier 
2779ef1f84bSDavid du Colombier 	if(waserror()) {
2789ef1f84bSDavid du Colombier 		mntfree(r);
2799ef1f84bSDavid du Colombier 		nexterror();
2809ef1f84bSDavid du Colombier 	}
2819ef1f84bSDavid du Colombier 
2829ef1f84bSDavid du Colombier 	r->request.type = Tauth;
2839ef1f84bSDavid du Colombier 	r->request.afid = c->fid;
2849ef1f84bSDavid du Colombier 	r->request.uname = up->user;
2859ef1f84bSDavid du Colombier 	r->request.aname = spec;
2869ef1f84bSDavid du Colombier 	mountrpc(mnt, r);
2879ef1f84bSDavid du Colombier 
2889ef1f84bSDavid du Colombier 	c->qid = r->reply.aqid;
2899ef1f84bSDavid du Colombier 	c->mchan = mnt->c;
2909ef1f84bSDavid du Colombier 	incref(mnt->c);
2919ef1f84bSDavid du Colombier 	c->mqid = c->qid;
2929ef1f84bSDavid du Colombier 	c->mode = ORDWR;
2939ef1f84bSDavid du Colombier 
2949ef1f84bSDavid du Colombier 	poperror();	/* r */
2959ef1f84bSDavid du Colombier 	mntfree(r);
2969ef1f84bSDavid du Colombier 
2979ef1f84bSDavid du Colombier 	poperror();	/* c */
2989ef1f84bSDavid du Colombier 
2999ef1f84bSDavid du Colombier 	return c;
3009ef1f84bSDavid du Colombier 
3019ef1f84bSDavid du Colombier }
3029ef1f84bSDavid du Colombier 
3039ef1f84bSDavid du Colombier static Chan*
mntattach(char * muxattach)3049ef1f84bSDavid du Colombier mntattach(char *muxattach)
3059ef1f84bSDavid du Colombier {
3069ef1f84bSDavid du Colombier 	Mnt *mnt;
3079ef1f84bSDavid du Colombier 	Chan *c;
3089ef1f84bSDavid du Colombier 	Mntrpc *r;
3099ef1f84bSDavid du Colombier 	struct bogus{
3109ef1f84bSDavid du Colombier 		Chan	*chan;
3119ef1f84bSDavid du Colombier 		Chan	*authchan;
3129ef1f84bSDavid du Colombier 		char	*spec;
3139ef1f84bSDavid du Colombier 		int	flags;
3149ef1f84bSDavid du Colombier 	}bogus;
3159ef1f84bSDavid du Colombier 
3169ef1f84bSDavid du Colombier 	bogus = *((struct bogus *)muxattach);
3179ef1f84bSDavid du Colombier 	c = bogus.chan;
3189ef1f84bSDavid du Colombier 
3199ef1f84bSDavid du Colombier 	mnt = c->mux;
3209ef1f84bSDavid du Colombier 
3219ef1f84bSDavid du Colombier 	if(mnt == nil){
3229ef1f84bSDavid du Colombier 		mntversion(c, 0, nil, 0);
3239ef1f84bSDavid du Colombier 		mnt = c->mux;
3249ef1f84bSDavid du Colombier 		if(mnt == nil)
3259ef1f84bSDavid du Colombier 			error(Enoversion);
3269ef1f84bSDavid du Colombier 	}
3279ef1f84bSDavid du Colombier 
3289ef1f84bSDavid du Colombier 	c = mntchan();
3299ef1f84bSDavid du Colombier 	if(waserror()) {
3309ef1f84bSDavid du Colombier 		/* Close must not be called since it will
3319ef1f84bSDavid du Colombier 		 * call mnt recursively
3329ef1f84bSDavid du Colombier 		 */
3339ef1f84bSDavid du Colombier 		chanfree(c);
3349ef1f84bSDavid du Colombier 		nexterror();
3359ef1f84bSDavid du Colombier 	}
3369ef1f84bSDavid du Colombier 
3379ef1f84bSDavid du Colombier 	r = mntralloc(0, mnt->msize);
3389ef1f84bSDavid du Colombier 
3399ef1f84bSDavid du Colombier 	if(waserror()) {
3409ef1f84bSDavid du Colombier 		mntfree(r);
3419ef1f84bSDavid du Colombier 		nexterror();
3429ef1f84bSDavid du Colombier 	}
3439ef1f84bSDavid du Colombier 
3449ef1f84bSDavid du Colombier 	r->request.type = Tattach;
3459ef1f84bSDavid du Colombier 	r->request.fid = c->fid;
3469ef1f84bSDavid du Colombier 	if(bogus.authchan == nil)
3479ef1f84bSDavid du Colombier 		r->request.afid = NOFID;
3489ef1f84bSDavid du Colombier 	else
3499ef1f84bSDavid du Colombier 		r->request.afid = bogus.authchan->fid;
3509ef1f84bSDavid du Colombier 	r->request.uname = up->user;
3519ef1f84bSDavid du Colombier 	r->request.aname = bogus.spec;
3529ef1f84bSDavid du Colombier 	mountrpc(mnt, r);
3539ef1f84bSDavid du Colombier 
3549ef1f84bSDavid du Colombier 	c->qid = r->reply.qid;
3559ef1f84bSDavid du Colombier 	c->mchan = mnt->c;
3569ef1f84bSDavid du Colombier 	incref(mnt->c);
3579ef1f84bSDavid du Colombier 	c->mqid = c->qid;
3589ef1f84bSDavid du Colombier 
3599ef1f84bSDavid du Colombier 	poperror();	/* r */
3609ef1f84bSDavid du Colombier 	mntfree(r);
3619ef1f84bSDavid du Colombier 
3629ef1f84bSDavid du Colombier 	poperror();	/* c */
3639ef1f84bSDavid du Colombier 
3649ef1f84bSDavid du Colombier 	if(bogus.flags & MCACHE)
3659ef1f84bSDavid du Colombier 		c->flag |= CCACHE;
3669ef1f84bSDavid du Colombier 	return c;
3679ef1f84bSDavid du Colombier }
3689ef1f84bSDavid du Colombier 
3699ef1f84bSDavid du Colombier Chan*
mntchan(void)3709ef1f84bSDavid du Colombier mntchan(void)
3719ef1f84bSDavid du Colombier {
3729ef1f84bSDavid du Colombier 	Chan *c;
3739ef1f84bSDavid du Colombier 
3749ef1f84bSDavid du Colombier 	c = devattach('M', 0);
3759ef1f84bSDavid du Colombier 	lock(&mntalloc);
3769ef1f84bSDavid du Colombier 	c->devno = mntalloc.id++;
3779ef1f84bSDavid du Colombier 	unlock(&mntalloc);
3789ef1f84bSDavid du Colombier 
3799ef1f84bSDavid du Colombier 	if(c->mchan)
3809ef1f84bSDavid du Colombier 		panic("mntchan non-zero %#p", c->mchan);
3819ef1f84bSDavid du Colombier 	return c;
3829ef1f84bSDavid du Colombier }
3839ef1f84bSDavid du Colombier 
3849ef1f84bSDavid du Colombier static Walkqid*
mntwalk(Chan * c,Chan * nc,char ** name,int nname)3859ef1f84bSDavid du Colombier mntwalk(Chan *c, Chan *nc, char **name, int nname)
3869ef1f84bSDavid du Colombier {
3879ef1f84bSDavid du Colombier 	int i, alloc;
3889ef1f84bSDavid du Colombier 	Mnt *mnt;
3899ef1f84bSDavid du Colombier 	Mntrpc *r;
3909ef1f84bSDavid du Colombier 	Walkqid *wq;
3919ef1f84bSDavid du Colombier 
3929ef1f84bSDavid du Colombier 	if(nc != nil)
3939ef1f84bSDavid du Colombier 		print("mntwalk: nc != nil\n");
3949ef1f84bSDavid du Colombier 	if(nname > MAXWELEM)
3959ef1f84bSDavid du Colombier 		error("devmnt: too many name elements");
3969ef1f84bSDavid du Colombier 	alloc = 0;
3979ef1f84bSDavid du Colombier 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
3989ef1f84bSDavid du Colombier 	if(waserror()){
3999ef1f84bSDavid du Colombier 		if(alloc && wq->clone!=nil)
4009ef1f84bSDavid du Colombier 			cclose(wq->clone);
4019ef1f84bSDavid du Colombier 		free(wq);
4029ef1f84bSDavid du Colombier 		return nil;
4039ef1f84bSDavid du Colombier 	}
4049ef1f84bSDavid du Colombier 
4059ef1f84bSDavid du Colombier 	alloc = 0;
4069ef1f84bSDavid du Colombier 	mnt = mntchk(c);
4079ef1f84bSDavid du Colombier 	r = mntralloc(c, mnt->msize);
4089ef1f84bSDavid du Colombier 	if(nc == nil){
4099ef1f84bSDavid du Colombier 		nc = devclone(c);
4109ef1f84bSDavid du Colombier 		/*
4119ef1f84bSDavid du Colombier 		 * Until the other side accepts this fid,
4129ef1f84bSDavid du Colombier 		 * we can't mntclose it.
4139ef1f84bSDavid du Colombier 		 * nc->dev remains nil for now.
4149ef1f84bSDavid du Colombier 		 */
4159ef1f84bSDavid du Colombier 		alloc = 1;
4169ef1f84bSDavid du Colombier 	}
4179ef1f84bSDavid du Colombier 	wq->clone = nc;
418406c76faSDavid du Colombier 	nc->flag |= c->flag&CCACHE;
4199ef1f84bSDavid du Colombier 
4209ef1f84bSDavid du Colombier 	if(waserror()) {
4219ef1f84bSDavid du Colombier 		mntfree(r);
4229ef1f84bSDavid du Colombier 		nexterror();
4239ef1f84bSDavid du Colombier 	}
4249ef1f84bSDavid du Colombier 	r->request.type = Twalk;
4259ef1f84bSDavid du Colombier 	r->request.fid = c->fid;
4269ef1f84bSDavid du Colombier 	r->request.newfid = nc->fid;
4279ef1f84bSDavid du Colombier 	r->request.nwname = nname;
4289ef1f84bSDavid du Colombier 	memmove(r->request.wname, name, nname*sizeof(char*));
4299ef1f84bSDavid du Colombier 
4309ef1f84bSDavid du Colombier 	mountrpc(mnt, r);
4319ef1f84bSDavid du Colombier 
4329ef1f84bSDavid du Colombier 	if(r->reply.nwqid > nname)
4339ef1f84bSDavid du Colombier 		error("too many QIDs returned by walk");
4349ef1f84bSDavid du Colombier 	if(r->reply.nwqid < nname){
4359ef1f84bSDavid du Colombier 		if(alloc)
4369ef1f84bSDavid du Colombier 			cclose(nc);
4379ef1f84bSDavid du Colombier 		wq->clone = nil;
4389ef1f84bSDavid du Colombier 		if(r->reply.nwqid == 0){
4399ef1f84bSDavid du Colombier 			free(wq);
4409ef1f84bSDavid du Colombier 			wq = nil;
4419ef1f84bSDavid du Colombier 			goto Return;
4429ef1f84bSDavid du Colombier 		}
4439ef1f84bSDavid du Colombier 	}
4449ef1f84bSDavid du Colombier 
4459ef1f84bSDavid du Colombier 	/* move new fid onto mnt device and update its qid */
4469ef1f84bSDavid du Colombier 	if(wq->clone != nil){
4479ef1f84bSDavid du Colombier 		if(wq->clone != c){
4489ef1f84bSDavid du Colombier 			wq->clone->dev = c->dev;
4499ef1f84bSDavid du Colombier 			//if(wq->clone->dev != nil)	//XDYNX
4509ef1f84bSDavid du Colombier 			//	devtabincr(wq->clone->dev);
4519ef1f84bSDavid du Colombier 			wq->clone->mchan = c->mchan;
4529ef1f84bSDavid du Colombier 			incref(c->mchan);
4539ef1f84bSDavid du Colombier 		}
4549ef1f84bSDavid du Colombier 		if(r->reply.nwqid > 0)
4559ef1f84bSDavid du Colombier 			wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
4569ef1f84bSDavid du Colombier 	}
4579ef1f84bSDavid du Colombier 	wq->nqid = r->reply.nwqid;
4589ef1f84bSDavid du Colombier 	for(i=0; i<wq->nqid; i++)
4599ef1f84bSDavid du Colombier 		wq->qid[i] = r->reply.wqid[i];
4609ef1f84bSDavid du Colombier 
4619ef1f84bSDavid du Colombier     Return:
4629ef1f84bSDavid du Colombier 	poperror();
4639ef1f84bSDavid du Colombier 	mntfree(r);
4649ef1f84bSDavid du Colombier 	poperror();
4659ef1f84bSDavid du Colombier 	return wq;
4669ef1f84bSDavid du Colombier }
4679ef1f84bSDavid du Colombier 
4689ef1f84bSDavid du Colombier static long
mntstat(Chan * c,uchar * dp,long n)4699ef1f84bSDavid du Colombier mntstat(Chan *c, uchar *dp, long n)
4709ef1f84bSDavid du Colombier {
4719ef1f84bSDavid du Colombier 	Mnt *mnt;
4729ef1f84bSDavid du Colombier 	Mntrpc *r;
4739ef1f84bSDavid du Colombier 	usize nstat;
4749ef1f84bSDavid du Colombier 
4759ef1f84bSDavid du Colombier 	if(n < BIT16SZ)
4769ef1f84bSDavid du Colombier 		error(Eshortstat);
4779ef1f84bSDavid du Colombier 	mnt = mntchk(c);
4789ef1f84bSDavid du Colombier 	r = mntralloc(c, mnt->msize);
4799ef1f84bSDavid du Colombier 	if(waserror()) {
4809ef1f84bSDavid du Colombier 		mntfree(r);
4819ef1f84bSDavid du Colombier 		nexterror();
4829ef1f84bSDavid du Colombier 	}
4839ef1f84bSDavid du Colombier 	r->request.type = Tstat;
4849ef1f84bSDavid du Colombier 	r->request.fid = c->fid;
4859ef1f84bSDavid du Colombier 	mountrpc(mnt, r);
4869ef1f84bSDavid du Colombier 
4879ef1f84bSDavid du Colombier 	if(r->reply.nstat > n){
4889ef1f84bSDavid du Colombier 		nstat = BIT16SZ;
4899ef1f84bSDavid du Colombier 		PBIT16(dp, r->reply.nstat-2);
4909ef1f84bSDavid du Colombier 	}else{
4919ef1f84bSDavid du Colombier 		nstat = r->reply.nstat;
4929ef1f84bSDavid du Colombier 		memmove(dp, r->reply.stat, nstat);
4939ef1f84bSDavid du Colombier 		validstat(dp, nstat);
4949ef1f84bSDavid du Colombier 		mntdirfix(dp, c);
4959ef1f84bSDavid du Colombier 	}
4969ef1f84bSDavid du Colombier 	poperror();
4979ef1f84bSDavid du Colombier 	mntfree(r);
4989ef1f84bSDavid du Colombier 
4999ef1f84bSDavid du Colombier 	return nstat;
5009ef1f84bSDavid du Colombier }
5019ef1f84bSDavid du Colombier 
5029ef1f84bSDavid du Colombier static Chan*
mntopencreate(int type,Chan * c,char * name,int omode,int perm)5039ef1f84bSDavid du Colombier mntopencreate(int type, Chan *c, char *name, int omode, int perm)
5049ef1f84bSDavid du Colombier {
5059ef1f84bSDavid du Colombier 	Mnt *mnt;
5069ef1f84bSDavid du Colombier 	Mntrpc *r;
5079ef1f84bSDavid du Colombier 
5089ef1f84bSDavid du Colombier 	mnt = mntchk(c);
5099ef1f84bSDavid du Colombier 	r = mntralloc(c, mnt->msize);
5109ef1f84bSDavid du Colombier 	if(waserror()) {
5119ef1f84bSDavid du Colombier 		mntfree(r);
5129ef1f84bSDavid du Colombier 		nexterror();
5139ef1f84bSDavid du Colombier 	}
5149ef1f84bSDavid du Colombier 	r->request.type = type;
5159ef1f84bSDavid du Colombier 	r->request.fid = c->fid;
5169ef1f84bSDavid du Colombier 	r->request.mode = omode;
5179ef1f84bSDavid du Colombier 	if(type == Tcreate){
5189ef1f84bSDavid du Colombier 		r->request.perm = perm;
5199ef1f84bSDavid du Colombier 		r->request.name = name;
5209ef1f84bSDavid du Colombier 	}
5219ef1f84bSDavid du Colombier 	mountrpc(mnt, r);
5229ef1f84bSDavid du Colombier 
5239ef1f84bSDavid du Colombier 	c->qid = r->reply.qid;
5249ef1f84bSDavid du Colombier 	c->offset = 0;
5259ef1f84bSDavid du Colombier 	c->mode = openmode(omode);
5269ef1f84bSDavid du Colombier 	c->iounit = r->reply.iounit;
5279ef1f84bSDavid du Colombier 	if(c->iounit == 0 || c->iounit > mnt->msize-IOHDRSZ)
5289ef1f84bSDavid du Colombier 		c->iounit = mnt->msize-IOHDRSZ;
5299ef1f84bSDavid du Colombier 	c->flag |= COPEN;
5309ef1f84bSDavid du Colombier 	poperror();
5319ef1f84bSDavid du Colombier 	mntfree(r);
5329ef1f84bSDavid du Colombier 
5339ef1f84bSDavid du Colombier 	if(c->flag & CCACHE)
5349ef1f84bSDavid du Colombier 		copen(c);
5359ef1f84bSDavid du Colombier 
5369ef1f84bSDavid du Colombier 	return c;
5379ef1f84bSDavid du Colombier }
5389ef1f84bSDavid du Colombier 
5399ef1f84bSDavid du Colombier static Chan*
mntopen(Chan * c,int omode)5409ef1f84bSDavid du Colombier mntopen(Chan *c, int omode)
5419ef1f84bSDavid du Colombier {
5429ef1f84bSDavid du Colombier 	return mntopencreate(Topen, c, nil, omode, 0);
5439ef1f84bSDavid du Colombier }
5449ef1f84bSDavid du Colombier 
5459ef1f84bSDavid du Colombier static void
mntcreate(Chan * c,char * name,int omode,int perm)5469ef1f84bSDavid du Colombier mntcreate(Chan *c, char *name, int omode, int perm)
5479ef1f84bSDavid du Colombier {
5489ef1f84bSDavid du Colombier 	mntopencreate(Tcreate, c, name, omode, perm);
5499ef1f84bSDavid du Colombier }
5509ef1f84bSDavid du Colombier 
5519ef1f84bSDavid du Colombier static void
mntclunk(Chan * c,int t)5529ef1f84bSDavid du Colombier mntclunk(Chan *c, int t)
5539ef1f84bSDavid du Colombier {
5549ef1f84bSDavid du Colombier 	Mnt *mnt;
5559ef1f84bSDavid du Colombier 	Mntrpc *r;
5569ef1f84bSDavid du Colombier 
5579ef1f84bSDavid du Colombier 	mnt = mntchk(c);
5589ef1f84bSDavid du Colombier 	r = mntralloc(c, mnt->msize);
5599ef1f84bSDavid du Colombier 	if(waserror()){
5609ef1f84bSDavid du Colombier 		mntfree(r);
5619ef1f84bSDavid du Colombier 		nexterror();
5629ef1f84bSDavid du Colombier 	}
5639ef1f84bSDavid du Colombier 
5649ef1f84bSDavid du Colombier 	r->request.type = t;
5659ef1f84bSDavid du Colombier 	r->request.fid = c->fid;
5669ef1f84bSDavid du Colombier 	mountrpc(mnt, r);
5679ef1f84bSDavid du Colombier 	mntfree(r);
5689ef1f84bSDavid du Colombier 	poperror();
5699ef1f84bSDavid du Colombier }
5709ef1f84bSDavid du Colombier 
5719ef1f84bSDavid du Colombier void
muxclose(Mnt * mnt)5729ef1f84bSDavid du Colombier muxclose(Mnt *mnt)
5739ef1f84bSDavid du Colombier {
5749ef1f84bSDavid du Colombier 	Mntrpc *q, *r;
5759ef1f84bSDavid du Colombier 
5769ef1f84bSDavid du Colombier 	for(q = mnt->queue; q; q = r) {
5779ef1f84bSDavid du Colombier 		r = q->list;
5789ef1f84bSDavid du Colombier 		mntfree(q);
5799ef1f84bSDavid du Colombier 	}
5809ef1f84bSDavid du Colombier 	mnt->id = 0;
5819ef1f84bSDavid du Colombier 	free(mnt->version);
5829ef1f84bSDavid du Colombier 	mnt->version = nil;
5839ef1f84bSDavid du Colombier 	mntpntfree(mnt);
5849ef1f84bSDavid du Colombier }
5859ef1f84bSDavid du Colombier 
5869ef1f84bSDavid du Colombier void
mntpntfree(Mnt * mnt)5879ef1f84bSDavid du Colombier mntpntfree(Mnt *mnt)
5889ef1f84bSDavid du Colombier {
5899ef1f84bSDavid du Colombier 	Mnt *f, **l;
5909ef1f84bSDavid du Colombier 	Queue *q;
5919ef1f84bSDavid du Colombier 
5929ef1f84bSDavid du Colombier 	lock(&mntalloc);
5939ef1f84bSDavid du Colombier 	l = &mntalloc.list;
5949ef1f84bSDavid du Colombier 	for(f = *l; f; f = f->list) {
5959ef1f84bSDavid du Colombier 		if(f == mnt) {
5969ef1f84bSDavid du Colombier 			*l = mnt->list;
5979ef1f84bSDavid du Colombier 			break;
5989ef1f84bSDavid du Colombier 		}
5999ef1f84bSDavid du Colombier 		l = &f->list;
6009ef1f84bSDavid du Colombier 	}
6019ef1f84bSDavid du Colombier 	mnt->list = mntalloc.mntfree;
6029ef1f84bSDavid du Colombier 	mntalloc.mntfree = mnt;
6039ef1f84bSDavid du Colombier 	q = mnt->q;
6049ef1f84bSDavid du Colombier 	unlock(&mntalloc);
6059ef1f84bSDavid du Colombier 
6069ef1f84bSDavid du Colombier 	qfree(q);
6079ef1f84bSDavid du Colombier }
6089ef1f84bSDavid du Colombier 
6099ef1f84bSDavid du Colombier static void
mntclose(Chan * c)6109ef1f84bSDavid du Colombier mntclose(Chan *c)
6119ef1f84bSDavid du Colombier {
6129ef1f84bSDavid du Colombier 	mntclunk(c, Tclunk);
6139ef1f84bSDavid du Colombier }
6149ef1f84bSDavid du Colombier 
6159ef1f84bSDavid du Colombier static void
mntremove(Chan * c)6169ef1f84bSDavid du Colombier mntremove(Chan *c)
6179ef1f84bSDavid du Colombier {
6189ef1f84bSDavid du Colombier 	mntclunk(c, Tremove);
6199ef1f84bSDavid du Colombier }
6209ef1f84bSDavid du Colombier 
6219ef1f84bSDavid du Colombier static long
mntwstat(Chan * c,uchar * dp,long n)6229ef1f84bSDavid du Colombier mntwstat(Chan *c, uchar *dp, long n)
6239ef1f84bSDavid du Colombier {
6249ef1f84bSDavid du Colombier 	Mnt *mnt;
6259ef1f84bSDavid du Colombier 	Mntrpc *r;
6269ef1f84bSDavid du Colombier 
6279ef1f84bSDavid du Colombier 	mnt = mntchk(c);
6289ef1f84bSDavid du Colombier 	r = mntralloc(c, mnt->msize);
6299ef1f84bSDavid du Colombier 	if(waserror()) {
6309ef1f84bSDavid du Colombier 		mntfree(r);
6319ef1f84bSDavid du Colombier 		nexterror();
6329ef1f84bSDavid du Colombier 	}
6339ef1f84bSDavid du Colombier 	r->request.type = Twstat;
6349ef1f84bSDavid du Colombier 	r->request.fid = c->fid;
6359ef1f84bSDavid du Colombier 	r->request.nstat = n;
6369ef1f84bSDavid du Colombier 	r->request.stat = dp;
6379ef1f84bSDavid du Colombier 	mountrpc(mnt, r);
6389ef1f84bSDavid du Colombier 	poperror();
6399ef1f84bSDavid du Colombier 	mntfree(r);
6409ef1f84bSDavid du Colombier 	return n;
6419ef1f84bSDavid du Colombier }
6429ef1f84bSDavid du Colombier 
6439ef1f84bSDavid du Colombier static long
mntread(Chan * c,void * buf,long n,vlong off)6449ef1f84bSDavid du Colombier mntread(Chan *c, void *buf, long n, vlong off)
6459ef1f84bSDavid du Colombier {
6469ef1f84bSDavid du Colombier 	uchar *p, *e;
6479ef1f84bSDavid du Colombier 	int nc, cache, isdir;
6489ef1f84bSDavid du Colombier 	usize dirlen;
6499ef1f84bSDavid du Colombier 
6509ef1f84bSDavid du Colombier 	isdir = 0;
6519ef1f84bSDavid du Colombier 	cache = c->flag & CCACHE;
6529ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR) {
6539ef1f84bSDavid du Colombier 		cache = 0;
6549ef1f84bSDavid du Colombier 		isdir = 1;
6559ef1f84bSDavid du Colombier 	}
6569ef1f84bSDavid du Colombier 
6579ef1f84bSDavid du Colombier 	p = buf;
6589ef1f84bSDavid du Colombier 	if(cache) {
6599ef1f84bSDavid du Colombier 		nc = cread(c, buf, n, off);
6609ef1f84bSDavid du Colombier 		if(nc > 0) {
6619ef1f84bSDavid du Colombier 			n -= nc;
6629ef1f84bSDavid du Colombier 			if(n == 0)
6639ef1f84bSDavid du Colombier 				return nc;
6649ef1f84bSDavid du Colombier 			p += nc;
6659ef1f84bSDavid du Colombier 			off += nc;
6669ef1f84bSDavid du Colombier 		}
6679ef1f84bSDavid du Colombier 		n = mntrdwr(Tread, c, p, n, off);
6689ef1f84bSDavid du Colombier 		cupdate(c, p, n, off);
6699ef1f84bSDavid du Colombier 		return n + nc;
6709ef1f84bSDavid du Colombier 	}
6719ef1f84bSDavid du Colombier 
6729ef1f84bSDavid du Colombier 	n = mntrdwr(Tread, c, buf, n, off);
6739ef1f84bSDavid du Colombier 	if(isdir) {
6749ef1f84bSDavid du Colombier 		for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
6759ef1f84bSDavid du Colombier 			dirlen = BIT16SZ+GBIT16(p);
6769ef1f84bSDavid du Colombier 			if(p+dirlen > e)
6779ef1f84bSDavid du Colombier 				break;
6789ef1f84bSDavid du Colombier 			validstat(p, dirlen);
6799ef1f84bSDavid du Colombier 			mntdirfix(p, c);
6809ef1f84bSDavid du Colombier 		}
6819ef1f84bSDavid du Colombier 		if(p != e)
6829ef1f84bSDavid du Colombier 			error(Esbadstat);
6839ef1f84bSDavid du Colombier 	}
6849ef1f84bSDavid du Colombier 	return n;
6859ef1f84bSDavid du Colombier }
6869ef1f84bSDavid du Colombier 
6879ef1f84bSDavid du Colombier static long
mntwrite(Chan * c,void * buf,long n,vlong off)6889ef1f84bSDavid du Colombier mntwrite(Chan *c, void *buf, long n, vlong off)
6899ef1f84bSDavid du Colombier {
6909ef1f84bSDavid du Colombier 	return mntrdwr(Twrite, c, buf, n, off);
6919ef1f84bSDavid du Colombier }
6929ef1f84bSDavid du Colombier 
6939ef1f84bSDavid du Colombier long
mntrdwr(int type,Chan * c,void * buf,long n,vlong off)6949ef1f84bSDavid du Colombier mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
6959ef1f84bSDavid du Colombier {
6969ef1f84bSDavid du Colombier 	Mnt *mnt;
6979ef1f84bSDavid du Colombier 	Mntrpc *r;
6989ef1f84bSDavid du Colombier 	char *uba;
6999ef1f84bSDavid du Colombier 	int cache;
7009ef1f84bSDavid du Colombier 	ulong cnt, nr, nreq;
7019ef1f84bSDavid du Colombier 
7029ef1f84bSDavid du Colombier 	mnt = mntchk(c);
7039ef1f84bSDavid du Colombier 	uba = buf;
7049ef1f84bSDavid du Colombier 	cnt = 0;
7059ef1f84bSDavid du Colombier 	cache = c->flag & CCACHE;
7069ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
7079ef1f84bSDavid du Colombier 		cache = 0;
7089ef1f84bSDavid du Colombier 	for(;;) {
7099ef1f84bSDavid du Colombier 		r = mntralloc(c, mnt->msize);
7109ef1f84bSDavid du Colombier 		if(waserror()) {
7119ef1f84bSDavid du Colombier 			mntfree(r);
7129ef1f84bSDavid du Colombier 			nexterror();
7139ef1f84bSDavid du Colombier 		}
7149ef1f84bSDavid du Colombier 		r->request.type = type;
7159ef1f84bSDavid du Colombier 		r->request.fid = c->fid;
7169ef1f84bSDavid du Colombier 		r->request.offset = off;
7179ef1f84bSDavid du Colombier 		r->request.data = uba;
7189ef1f84bSDavid du Colombier 		nr = n;
7199ef1f84bSDavid du Colombier 		if(nr > mnt->msize-IOHDRSZ)
7209ef1f84bSDavid du Colombier 			nr = mnt->msize-IOHDRSZ;
7219ef1f84bSDavid du Colombier 		r->request.count = nr;
7229ef1f84bSDavid du Colombier 		mountrpc(mnt, r);
7239ef1f84bSDavid du Colombier 		nreq = r->request.count;
7249ef1f84bSDavid du Colombier 		nr = r->reply.count;
7259ef1f84bSDavid du Colombier 		if(nr > nreq)
7269ef1f84bSDavid du Colombier 			nr = nreq;
7279ef1f84bSDavid du Colombier 
7289ef1f84bSDavid du Colombier 		if(type == Tread)
7299ef1f84bSDavid du Colombier 			r->b = bl2mem((uchar*)uba, r->b, nr);
7309ef1f84bSDavid du Colombier 		else if(cache)
7319ef1f84bSDavid du Colombier 			cwrite(c, (uchar*)uba, nr, off);
7329ef1f84bSDavid du Colombier 
7339ef1f84bSDavid du Colombier 		poperror();
7349ef1f84bSDavid du Colombier 		mntfree(r);
7359ef1f84bSDavid du Colombier 		off += nr;
7369ef1f84bSDavid du Colombier 		uba += nr;
7379ef1f84bSDavid du Colombier 		cnt += nr;
7389ef1f84bSDavid du Colombier 		n -= nr;
7399ef1f84bSDavid du Colombier 		if(nr != nreq || n == 0 || up->nnote)
7409ef1f84bSDavid du Colombier 			break;
7419ef1f84bSDavid du Colombier 	}
7429ef1f84bSDavid du Colombier 	return cnt;
7439ef1f84bSDavid du Colombier }
7449ef1f84bSDavid du Colombier 
7459ef1f84bSDavid du Colombier void
mountrpc(Mnt * mnt,Mntrpc * r)7469ef1f84bSDavid du Colombier mountrpc(Mnt *mnt, Mntrpc *r)
7479ef1f84bSDavid du Colombier {
7489ef1f84bSDavid du Colombier 	char *sn, *cn;
7499ef1f84bSDavid du Colombier 	int t;
7509ef1f84bSDavid du Colombier 
7519ef1f84bSDavid du Colombier 	r->reply.tag = 0;
7529ef1f84bSDavid du Colombier 	r->reply.type = Tmax;	/* can't ever be a valid message type */
7539ef1f84bSDavid du Colombier 
7549ef1f84bSDavid du Colombier 	mountio(mnt, r);
7559ef1f84bSDavid du Colombier 
7569ef1f84bSDavid du Colombier 	t = r->reply.type;
7579ef1f84bSDavid du Colombier 	switch(t) {
7589ef1f84bSDavid du Colombier 	case Rerror:
7599ef1f84bSDavid du Colombier 		error(r->reply.ename);
7609ef1f84bSDavid du Colombier 	case Rflush:
7619ef1f84bSDavid du Colombier 		error(Eintr);
7629ef1f84bSDavid du Colombier 	default:
7639ef1f84bSDavid du Colombier 		if(t == r->request.type+1)
7649ef1f84bSDavid du Colombier 			break;
7659ef1f84bSDavid du Colombier 		sn = "?";
7669ef1f84bSDavid du Colombier 		if(mnt->c->path != nil)
7679ef1f84bSDavid du Colombier 			sn = mnt->c->path->s;
7689ef1f84bSDavid du Colombier 		cn = "?";
7699ef1f84bSDavid du Colombier 		if(r->c != nil && r->c->path != nil)
7709ef1f84bSDavid du Colombier 			cn = r->c->path->s;
7719ef1f84bSDavid du Colombier 		print("mnt: proc %s %d: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
7729ef1f84bSDavid du Colombier 			up->text, up->pid, sn, cn,
7739ef1f84bSDavid du Colombier 			r, r->request.tag, r->request.fid, r->request.type,
7749ef1f84bSDavid du Colombier 			r->reply.type, r->reply.tag);
7759ef1f84bSDavid du Colombier 		error(Emountrpc);
7769ef1f84bSDavid du Colombier 	}
7779ef1f84bSDavid du Colombier }
7789ef1f84bSDavid du Colombier 
7799ef1f84bSDavid du Colombier void
mountio(Mnt * mnt,Mntrpc * r)7809ef1f84bSDavid du Colombier mountio(Mnt *mnt, Mntrpc *r)
7819ef1f84bSDavid du Colombier {
7829ef1f84bSDavid du Colombier 	int n;
7839ef1f84bSDavid du Colombier 
7849ef1f84bSDavid du Colombier 	while(waserror()) {
7859ef1f84bSDavid du Colombier 		if(mnt->rip == up)
7869ef1f84bSDavid du Colombier 			mntgate(mnt);
7879ef1f84bSDavid du Colombier 		if(strcmp(up->errstr, Eintr) != 0){
7889ef1f84bSDavid du Colombier 			mntflushfree(mnt, r);
7899ef1f84bSDavid du Colombier 			nexterror();
7909ef1f84bSDavid du Colombier 		}
7919ef1f84bSDavid du Colombier 		r = mntflushalloc(r, mnt->msize);
7929ef1f84bSDavid du Colombier 	}
7939ef1f84bSDavid du Colombier 
7949ef1f84bSDavid du Colombier 	lock(mnt);
7959ef1f84bSDavid du Colombier 	r->m = mnt;
7969ef1f84bSDavid du Colombier 	r->list = mnt->queue;
7979ef1f84bSDavid du Colombier 	mnt->queue = r;
7989ef1f84bSDavid du Colombier 	unlock(mnt);
7999ef1f84bSDavid du Colombier 
8009ef1f84bSDavid du Colombier 	/* Transmit a file system rpc */
8019ef1f84bSDavid du Colombier 	if(mnt->msize == 0)
8029ef1f84bSDavid du Colombier 		panic("msize");
8039ef1f84bSDavid du Colombier 	n = convS2M(&r->request, r->rpc, mnt->msize);
8049ef1f84bSDavid du Colombier 	if(n < 0)
8059ef1f84bSDavid du Colombier 		panic("bad message type in mountio");
8069ef1f84bSDavid du Colombier 	if(mnt->c->dev->write(mnt->c, r->rpc, n, 0) != n)
8079ef1f84bSDavid du Colombier 		error(Emountrpc);
8089ef1f84bSDavid du Colombier 	r->stime = fastticks(nil);
8099ef1f84bSDavid du Colombier 	r->reqlen = n;
8109ef1f84bSDavid du Colombier 
8119ef1f84bSDavid du Colombier 	/* Gate readers onto the mount point one at a time */
8129ef1f84bSDavid du Colombier 	for(;;) {
8139ef1f84bSDavid du Colombier 		lock(mnt);
8149ef1f84bSDavid du Colombier 		if(mnt->rip == 0)
8159ef1f84bSDavid du Colombier 			break;
8169ef1f84bSDavid du Colombier 		unlock(mnt);
8179ef1f84bSDavid du Colombier 		sleep(&r->r, rpcattn, r);
8189ef1f84bSDavid du Colombier 		if(r->done){
8199ef1f84bSDavid du Colombier 			poperror();
8209ef1f84bSDavid du Colombier 			mntflushfree(mnt, r);
8219ef1f84bSDavid du Colombier 			return;
8229ef1f84bSDavid du Colombier 		}
8239ef1f84bSDavid du Colombier 	}
8249ef1f84bSDavid du Colombier 	mnt->rip = up;
8259ef1f84bSDavid du Colombier 	unlock(mnt);
8269ef1f84bSDavid du Colombier 	while(r->done == 0) {
8279ef1f84bSDavid du Colombier 		if(mntrpcread(mnt, r) < 0)
8289ef1f84bSDavid du Colombier 			error(Emountrpc);
8299ef1f84bSDavid du Colombier 		mountmux(mnt, r);
8309ef1f84bSDavid du Colombier 	}
8319ef1f84bSDavid du Colombier 	mntgate(mnt);
8329ef1f84bSDavid du Colombier 	poperror();
8339ef1f84bSDavid du Colombier 	mntflushfree(mnt, r);
8349ef1f84bSDavid du Colombier }
8359ef1f84bSDavid du Colombier 
8369ef1f84bSDavid du Colombier static int
doread(Mnt * mnt,int len)8379ef1f84bSDavid du Colombier doread(Mnt *mnt, int len)
8389ef1f84bSDavid du Colombier {
8399ef1f84bSDavid du Colombier 	Block *b;
8409ef1f84bSDavid du Colombier 
8419ef1f84bSDavid du Colombier 	while(qlen(mnt->q) < len){
8429ef1f84bSDavid du Colombier 		b = mnt->c->dev->bread(mnt->c, mnt->msize, 0);
8439ef1f84bSDavid du Colombier 		if(b == nil)
8449ef1f84bSDavid du Colombier 			return -1;
8459ef1f84bSDavid du Colombier 		if(blocklen(b) == 0){
8469ef1f84bSDavid du Colombier 			freeblist(b);
8479ef1f84bSDavid du Colombier 			return -1;
8489ef1f84bSDavid du Colombier 		}
8499ef1f84bSDavid du Colombier 		qaddlist(mnt->q, b);
8509ef1f84bSDavid du Colombier 	}
8519ef1f84bSDavid du Colombier 	return 0;
8529ef1f84bSDavid du Colombier }
8539ef1f84bSDavid du Colombier 
8549ef1f84bSDavid du Colombier int
mntrpcread(Mnt * mnt,Mntrpc * r)8559ef1f84bSDavid du Colombier mntrpcread(Mnt *mnt, Mntrpc *r)
8569ef1f84bSDavid du Colombier {
8579ef1f84bSDavid du Colombier 	int i, t, len, hlen;
8589ef1f84bSDavid du Colombier 	Block *b, **l, *nb;
8599ef1f84bSDavid du Colombier 
8609ef1f84bSDavid du Colombier 	r->reply.type = 0;
8619ef1f84bSDavid du Colombier 	r->reply.tag = 0;
8629ef1f84bSDavid du Colombier 
8639ef1f84bSDavid du Colombier 	/* read at least length, type, and tag and pullup to a single block */
8649ef1f84bSDavid du Colombier 	if(doread(mnt, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
8659ef1f84bSDavid du Colombier 		return -1;
8669ef1f84bSDavid du Colombier 	nb = pullupqueue(mnt->q, BIT32SZ+BIT8SZ+BIT16SZ);
8679ef1f84bSDavid du Colombier 
8689ef1f84bSDavid du Colombier 	/* read in the rest of the message, avoid ridiculous (for now) message sizes */
8699ef1f84bSDavid du Colombier 	len = GBIT32(nb->rp);
8709ef1f84bSDavid du Colombier 	if(len > mnt->msize){
8719ef1f84bSDavid du Colombier 		qdiscard(mnt->q, qlen(mnt->q));
8729ef1f84bSDavid du Colombier 		return -1;
8739ef1f84bSDavid du Colombier 	}
8749ef1f84bSDavid du Colombier 	if(doread(mnt, len) < 0)
8759ef1f84bSDavid du Colombier 		return -1;
8769ef1f84bSDavid du Colombier 
8779ef1f84bSDavid du Colombier 	/* pullup the header (i.e. everything except data) */
8789ef1f84bSDavid du Colombier 	t = nb->rp[BIT32SZ];
8799ef1f84bSDavid du Colombier 	switch(t){
8809ef1f84bSDavid du Colombier 	case Rread:
8819ef1f84bSDavid du Colombier 		hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
8829ef1f84bSDavid du Colombier 		break;
8839ef1f84bSDavid du Colombier 	default:
8849ef1f84bSDavid du Colombier 		hlen = len;
8859ef1f84bSDavid du Colombier 		break;
8869ef1f84bSDavid du Colombier 	}
8879ef1f84bSDavid du Colombier 	nb = pullupqueue(mnt->q, hlen);
8889ef1f84bSDavid du Colombier 
8899ef1f84bSDavid du Colombier 	if(convM2S(nb->rp, len, &r->reply) <= 0){
8909ef1f84bSDavid du Colombier 		/* bad message, dump it */
8919ef1f84bSDavid du Colombier 		print("mntrpcread: convM2S failed\n");
8929ef1f84bSDavid du Colombier 		qdiscard(mnt->q, len);
8939ef1f84bSDavid du Colombier 		return -1;
8949ef1f84bSDavid du Colombier 	}
8959ef1f84bSDavid du Colombier 
8969ef1f84bSDavid du Colombier 	/* hang the data off of the fcall struct */
8979ef1f84bSDavid du Colombier 	l = &r->b;
8989ef1f84bSDavid du Colombier 	*l = nil;
8999ef1f84bSDavid du Colombier 	do {
9009ef1f84bSDavid du Colombier 		b = qremove(mnt->q);
9019ef1f84bSDavid du Colombier 		if(hlen > 0){
9029ef1f84bSDavid du Colombier 			b->rp += hlen;
9039ef1f84bSDavid du Colombier 			len -= hlen;
9049ef1f84bSDavid du Colombier 			hlen = 0;
9059ef1f84bSDavid du Colombier 		}
9069ef1f84bSDavid du Colombier 		i = BLEN(b);
9079ef1f84bSDavid du Colombier 		if(i <= len){
9089ef1f84bSDavid du Colombier 			len -= i;
9099ef1f84bSDavid du Colombier 			*l = b;
9109ef1f84bSDavid du Colombier 			l = &(b->next);
9119ef1f84bSDavid du Colombier 		} else {
9129ef1f84bSDavid du Colombier 			/* split block and put unused bit back */
9139ef1f84bSDavid du Colombier 			nb = allocb(i-len);
9149ef1f84bSDavid du Colombier 			memmove(nb->wp, b->rp+len, i-len);
9159ef1f84bSDavid du Colombier 			b->wp = b->rp+len;
9169ef1f84bSDavid du Colombier 			nb->wp += i-len;
9179ef1f84bSDavid du Colombier 			qputback(mnt->q, nb);
9189ef1f84bSDavid du Colombier 			*l = b;
9199ef1f84bSDavid du Colombier 			return 0;
9209ef1f84bSDavid du Colombier 		}
9219ef1f84bSDavid du Colombier 	}while(len > 0);
9229ef1f84bSDavid du Colombier 
9239ef1f84bSDavid du Colombier 	return 0;
9249ef1f84bSDavid du Colombier }
9259ef1f84bSDavid du Colombier 
9269ef1f84bSDavid du Colombier void
mntgate(Mnt * mnt)9279ef1f84bSDavid du Colombier mntgate(Mnt *mnt)
9289ef1f84bSDavid du Colombier {
9299ef1f84bSDavid du Colombier 	Mntrpc *q;
9309ef1f84bSDavid du Colombier 
9319ef1f84bSDavid du Colombier 	lock(mnt);
9329ef1f84bSDavid du Colombier 	mnt->rip = 0;
9339ef1f84bSDavid du Colombier 	for(q = mnt->queue; q; q = q->list) {
9349ef1f84bSDavid du Colombier 		if(q->done == 0)
9359ef1f84bSDavid du Colombier 		if(wakeup(&q->r))
9369ef1f84bSDavid du Colombier 			break;
9379ef1f84bSDavid du Colombier 	}
9389ef1f84bSDavid du Colombier 	unlock(mnt);
9399ef1f84bSDavid du Colombier }
9409ef1f84bSDavid du Colombier 
9419ef1f84bSDavid du Colombier void
mountmux(Mnt * mnt,Mntrpc * r)9429ef1f84bSDavid du Colombier mountmux(Mnt *mnt, Mntrpc *r)
9439ef1f84bSDavid du Colombier {
9449ef1f84bSDavid du Colombier 	Mntrpc **l, *q;
9459ef1f84bSDavid du Colombier 
9469ef1f84bSDavid du Colombier 	lock(mnt);
9479ef1f84bSDavid du Colombier 	l = &mnt->queue;
9489ef1f84bSDavid du Colombier 	for(q = *l; q; q = q->list) {
9499ef1f84bSDavid du Colombier 		/* look for a reply to a message */
9509ef1f84bSDavid du Colombier 		if(q->request.tag == r->reply.tag) {
9519ef1f84bSDavid du Colombier 			*l = q->list;
9529ef1f84bSDavid du Colombier 			if(q != r) {
9539ef1f84bSDavid du Colombier 				/*
9549ef1f84bSDavid du Colombier 				 * Completed someone else.
9559ef1f84bSDavid du Colombier 				 * Trade pointers to receive buffer.
9569ef1f84bSDavid du Colombier 				 */
9579ef1f84bSDavid du Colombier 				q->reply = r->reply;
9589ef1f84bSDavid du Colombier 				q->b = r->b;
9599ef1f84bSDavid du Colombier 				r->b = nil;
9609ef1f84bSDavid du Colombier 			}
9619ef1f84bSDavid du Colombier 			q->done = 1;
9629ef1f84bSDavid du Colombier 			unlock(mnt);
9639ef1f84bSDavid du Colombier 			if(mntstats != nil)
9649ef1f84bSDavid du Colombier 				(*mntstats)(q->request.type,
9659ef1f84bSDavid du Colombier 					mnt->c, q->stime,
9669ef1f84bSDavid du Colombier 					q->reqlen + r->replen);
9679ef1f84bSDavid du Colombier 			if(q != r)
9689ef1f84bSDavid du Colombier 				wakeup(&q->r);
9699ef1f84bSDavid du Colombier 			return;
9709ef1f84bSDavid du Colombier 		}
9719ef1f84bSDavid du Colombier 		l = &q->list;
9729ef1f84bSDavid du Colombier 	}
9739ef1f84bSDavid du Colombier 	unlock(mnt);
9749ef1f84bSDavid du Colombier 	print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
9759ef1f84bSDavid du Colombier }
9769ef1f84bSDavid du Colombier 
9779ef1f84bSDavid du Colombier /*
9789ef1f84bSDavid du Colombier  * Create a new flush request and chain the previous
9799ef1f84bSDavid du Colombier  * requests from it
9809ef1f84bSDavid du Colombier  */
9819ef1f84bSDavid du Colombier Mntrpc*
mntflushalloc(Mntrpc * r,ulong iounit)9829ef1f84bSDavid du Colombier mntflushalloc(Mntrpc *r, ulong iounit)
9839ef1f84bSDavid du Colombier {
9849ef1f84bSDavid du Colombier 	Mntrpc *fr;
9859ef1f84bSDavid du Colombier 
9869ef1f84bSDavid du Colombier 	fr = mntralloc(0, iounit);
9879ef1f84bSDavid du Colombier 
9889ef1f84bSDavid du Colombier 	fr->request.type = Tflush;
9899ef1f84bSDavid du Colombier 	if(r->request.type == Tflush)
9909ef1f84bSDavid du Colombier 		fr->request.oldtag = r->request.oldtag;
9919ef1f84bSDavid du Colombier 	else
9929ef1f84bSDavid du Colombier 		fr->request.oldtag = r->request.tag;
9939ef1f84bSDavid du Colombier 	fr->flushed = r;
9949ef1f84bSDavid du Colombier 
9959ef1f84bSDavid du Colombier 	return fr;
9969ef1f84bSDavid du Colombier }
9979ef1f84bSDavid du Colombier 
9989ef1f84bSDavid du Colombier /*
9999ef1f84bSDavid du Colombier  *  Free a chain of flushes.  Remove each unanswered
10009ef1f84bSDavid du Colombier  *  flush and the original message from the unanswered
10019ef1f84bSDavid du Colombier  *  request queue.  Mark the original message as done
10029ef1f84bSDavid du Colombier  *  and if it hasn't been answered set the reply to to
10039ef1f84bSDavid du Colombier  *  Rflush.
10049ef1f84bSDavid du Colombier  */
10059ef1f84bSDavid du Colombier void
mntflushfree(Mnt * mnt,Mntrpc * r)10069ef1f84bSDavid du Colombier mntflushfree(Mnt *mnt, Mntrpc *r)
10079ef1f84bSDavid du Colombier {
10089ef1f84bSDavid du Colombier 	Mntrpc *fr;
10099ef1f84bSDavid du Colombier 
10109ef1f84bSDavid du Colombier 	while(r){
10119ef1f84bSDavid du Colombier 		fr = r->flushed;
10129ef1f84bSDavid du Colombier 		if(!r->done){
10139ef1f84bSDavid du Colombier 			r->reply.type = Rflush;
10149ef1f84bSDavid du Colombier 			mntqrm(mnt, r);
10159ef1f84bSDavid du Colombier 		}
10169ef1f84bSDavid du Colombier 		if(fr)
10179ef1f84bSDavid du Colombier 			mntfree(r);
10189ef1f84bSDavid du Colombier 		r = fr;
10199ef1f84bSDavid du Colombier 	}
10209ef1f84bSDavid du Colombier }
10219ef1f84bSDavid du Colombier 
10229ef1f84bSDavid du Colombier int
alloctag(void)10239ef1f84bSDavid du Colombier alloctag(void)
10249ef1f84bSDavid du Colombier {
10259ef1f84bSDavid du Colombier 	int i, j;
10269ef1f84bSDavid du Colombier 	ulong v;
10279ef1f84bSDavid du Colombier 
10289ef1f84bSDavid du Colombier 	for(i = 0; i < NMASK; i++){
10299ef1f84bSDavid du Colombier 		v = mntalloc.tagmask[i];
10309ef1f84bSDavid du Colombier 		if(v == ~0UL)
10319ef1f84bSDavid du Colombier 			continue;
10329ef1f84bSDavid du Colombier 		for(j = 0; j < 1<<TAGSHIFT; j++)
10339ef1f84bSDavid du Colombier 			if((v & (1<<j)) == 0){
10349ef1f84bSDavid du Colombier 				mntalloc.tagmask[i] |= 1<<j;
10359ef1f84bSDavid du Colombier 				return (i<<TAGSHIFT) + j;
10369ef1f84bSDavid du Colombier 			}
10379ef1f84bSDavid du Colombier 	}
10389ef1f84bSDavid du Colombier 	panic("no friggin tags left");
10399ef1f84bSDavid du Colombier 	return NOTAG;
10409ef1f84bSDavid du Colombier }
10419ef1f84bSDavid du Colombier 
10429ef1f84bSDavid du Colombier void
freetag(int t)10439ef1f84bSDavid du Colombier freetag(int t)
10449ef1f84bSDavid du Colombier {
10459ef1f84bSDavid du Colombier 	mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
10469ef1f84bSDavid du Colombier }
10479ef1f84bSDavid du Colombier 
10489ef1f84bSDavid du Colombier Mntrpc*
mntralloc(Chan * c,ulong msize)10499ef1f84bSDavid du Colombier mntralloc(Chan *c, ulong msize)
10509ef1f84bSDavid du Colombier {
10519ef1f84bSDavid du Colombier 	Mntrpc *new;
10529ef1f84bSDavid du Colombier 
10539ef1f84bSDavid du Colombier 	lock(&mntalloc);
10549ef1f84bSDavid du Colombier 	new = mntalloc.rpcfree;
10559ef1f84bSDavid du Colombier 	if(new == nil){
10569ef1f84bSDavid du Colombier 		new = malloc(sizeof(Mntrpc));
10579ef1f84bSDavid du Colombier 		if(new == nil) {
10589ef1f84bSDavid du Colombier 			unlock(&mntalloc);
10599ef1f84bSDavid du Colombier 			exhausted("mount rpc header");
10609ef1f84bSDavid du Colombier 		}
10619ef1f84bSDavid du Colombier 		/*
10629ef1f84bSDavid du Colombier 		 * The header is split from the data buffer as
10639ef1f84bSDavid du Colombier 		 * mountmux may swap the buffer with another header.
10649ef1f84bSDavid du Colombier 		 */
10659ef1f84bSDavid du Colombier 		new->rpc = mallocz(msize, 0);
10669ef1f84bSDavid du Colombier 		if(new->rpc == nil){
10679ef1f84bSDavid du Colombier 			free(new);
10689ef1f84bSDavid du Colombier 			unlock(&mntalloc);
10699ef1f84bSDavid du Colombier 			exhausted("mount rpc buffer");
10709ef1f84bSDavid du Colombier 		}
10719ef1f84bSDavid du Colombier 		new->rpclen = msize;
10729ef1f84bSDavid du Colombier 		new->request.tag = alloctag();
10739ef1f84bSDavid du Colombier 	}
10749ef1f84bSDavid du Colombier 	else {
10759ef1f84bSDavid du Colombier 		mntalloc.rpcfree = new->list;
10769ef1f84bSDavid du Colombier 		mntalloc.nrpcfree--;
10779ef1f84bSDavid du Colombier 		if(new->rpclen < msize){
10789ef1f84bSDavid du Colombier 			free(new->rpc);
10799ef1f84bSDavid du Colombier 			new->rpc = mallocz(msize, 0);
10809ef1f84bSDavid du Colombier 			if(new->rpc == nil){
10819ef1f84bSDavid du Colombier 				free(new);
10829ef1f84bSDavid du Colombier 				mntalloc.nrpcused--;
10839ef1f84bSDavid du Colombier 				unlock(&mntalloc);
10849ef1f84bSDavid du Colombier 				exhausted("mount rpc buffer");
10859ef1f84bSDavid du Colombier 			}
10869ef1f84bSDavid du Colombier 			new->rpclen = msize;
10879ef1f84bSDavid du Colombier 		}
10889ef1f84bSDavid du Colombier 	}
10899ef1f84bSDavid du Colombier 	mntalloc.nrpcused++;
10909ef1f84bSDavid du Colombier 	unlock(&mntalloc);
10919ef1f84bSDavid du Colombier 	new->c = c;
10929ef1f84bSDavid du Colombier 	new->done = 0;
10939ef1f84bSDavid du Colombier 	new->flushed = nil;
10949ef1f84bSDavid du Colombier 	new->b = nil;
10959ef1f84bSDavid du Colombier 	return new;
10969ef1f84bSDavid du Colombier }
10979ef1f84bSDavid du Colombier 
10989ef1f84bSDavid du Colombier void
mntfree(Mntrpc * r)10999ef1f84bSDavid du Colombier mntfree(Mntrpc *r)
11009ef1f84bSDavid du Colombier {
11019ef1f84bSDavid du Colombier 	if(r->b != nil)
11029ef1f84bSDavid du Colombier 		freeblist(r->b);
11039ef1f84bSDavid du Colombier 	lock(&mntalloc);
11049ef1f84bSDavid du Colombier 	if(mntalloc.nrpcfree >= 10){
11059ef1f84bSDavid du Colombier 		free(r->rpc);
11069ef1f84bSDavid du Colombier 		freetag(r->request.tag);
11079ef1f84bSDavid du Colombier 		free(r);
11089ef1f84bSDavid du Colombier 	}
11099ef1f84bSDavid du Colombier 	else{
11109ef1f84bSDavid du Colombier 		r->list = mntalloc.rpcfree;
11119ef1f84bSDavid du Colombier 		mntalloc.rpcfree = r;
11129ef1f84bSDavid du Colombier 		mntalloc.nrpcfree++;
11139ef1f84bSDavid du Colombier 	}
11149ef1f84bSDavid du Colombier 	mntalloc.nrpcused--;
11159ef1f84bSDavid du Colombier 	unlock(&mntalloc);
11169ef1f84bSDavid du Colombier }
11179ef1f84bSDavid du Colombier 
11189ef1f84bSDavid du Colombier void
mntqrm(Mnt * mnt,Mntrpc * r)11199ef1f84bSDavid du Colombier mntqrm(Mnt *mnt, Mntrpc *r)
11209ef1f84bSDavid du Colombier {
11219ef1f84bSDavid du Colombier 	Mntrpc **l, *f;
11229ef1f84bSDavid du Colombier 
11239ef1f84bSDavid du Colombier 	lock(mnt);
11249ef1f84bSDavid du Colombier 	r->done = 1;
11259ef1f84bSDavid du Colombier 
11269ef1f84bSDavid du Colombier 	l = &mnt->queue;
11279ef1f84bSDavid du Colombier 	for(f = *l; f; f = f->list) {
11289ef1f84bSDavid du Colombier 		if(f == r) {
11299ef1f84bSDavid du Colombier 			*l = r->list;
11309ef1f84bSDavid du Colombier 			break;
11319ef1f84bSDavid du Colombier 		}
11329ef1f84bSDavid du Colombier 		l = &f->list;
11339ef1f84bSDavid du Colombier 	}
11349ef1f84bSDavid du Colombier 	unlock(mnt);
11359ef1f84bSDavid du Colombier }
11369ef1f84bSDavid du Colombier 
11379ef1f84bSDavid du Colombier Mnt*
mntchk(Chan * c)11389ef1f84bSDavid du Colombier mntchk(Chan *c)
11399ef1f84bSDavid du Colombier {
11409ef1f84bSDavid du Colombier 	Mnt *mnt;
11419ef1f84bSDavid du Colombier 
11429ef1f84bSDavid du Colombier 	/* This routine is mostly vestiges of prior lives; now it's just sanity checking */
11439ef1f84bSDavid du Colombier 
11449ef1f84bSDavid du Colombier 	if(c->mchan == nil)
11459ef1f84bSDavid du Colombier 		panic("mntchk 1: nil mchan c %s\n", chanpath(c));
11469ef1f84bSDavid du Colombier 
11479ef1f84bSDavid du Colombier 	mnt = c->mchan->mux;
11489ef1f84bSDavid du Colombier 
11499ef1f84bSDavid du Colombier 	if(mnt == nil)
11509ef1f84bSDavid du Colombier 		print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
11519ef1f84bSDavid du Colombier 
11529ef1f84bSDavid du Colombier 	/*
11539ef1f84bSDavid du Colombier 	 * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
11549ef1f84bSDavid du Colombier 	 */
11559ef1f84bSDavid du Colombier 	if(mnt->id == 0 || mnt->id >= c->devno)
11569ef1f84bSDavid du Colombier 		panic("mntchk 3: can't happen");
11579ef1f84bSDavid du Colombier 
11589ef1f84bSDavid du Colombier 	return mnt;
11599ef1f84bSDavid du Colombier }
11609ef1f84bSDavid du Colombier 
11619ef1f84bSDavid du Colombier /*
11629ef1f84bSDavid du Colombier  * Rewrite channel type and dev for in-flight data to
11639ef1f84bSDavid du Colombier  * reflect local values.  These entries are known to be
11649ef1f84bSDavid du Colombier  * the first two in the Dir encoding after the count.
11659ef1f84bSDavid du Colombier  */
11669ef1f84bSDavid du Colombier void
mntdirfix(uchar * dirbuf,Chan * c)11679ef1f84bSDavid du Colombier mntdirfix(uchar *dirbuf, Chan *c)
11689ef1f84bSDavid du Colombier {
11699ef1f84bSDavid du Colombier 	uint r;
11709ef1f84bSDavid du Colombier 
11719ef1f84bSDavid du Colombier 	r = c->dev->dc;
11729ef1f84bSDavid du Colombier 	dirbuf += BIT16SZ;	/* skip count */
11739ef1f84bSDavid du Colombier 	PBIT16(dirbuf, r);
11749ef1f84bSDavid du Colombier 	dirbuf += BIT16SZ;
11759ef1f84bSDavid du Colombier 	PBIT32(dirbuf, c->devno);
11769ef1f84bSDavid du Colombier }
11779ef1f84bSDavid du Colombier 
11789ef1f84bSDavid du Colombier int
rpcattn(void * v)11799ef1f84bSDavid du Colombier rpcattn(void *v)
11809ef1f84bSDavid du Colombier {
11819ef1f84bSDavid du Colombier 	Mntrpc *r;
11829ef1f84bSDavid du Colombier 
11839ef1f84bSDavid du Colombier 	r = v;
11849ef1f84bSDavid du Colombier 	return r->done || r->m->rip == 0;
11859ef1f84bSDavid du Colombier }
11869ef1f84bSDavid du Colombier 
11879ef1f84bSDavid du Colombier Dev mntdevtab = {
11889ef1f84bSDavid du Colombier 	'M',
11899ef1f84bSDavid du Colombier 	"mnt",
11909ef1f84bSDavid du Colombier 
11919ef1f84bSDavid du Colombier 	mntreset,
11929ef1f84bSDavid du Colombier 	devinit,
11939ef1f84bSDavid du Colombier 	devshutdown,
11949ef1f84bSDavid du Colombier 	mntattach,
11959ef1f84bSDavid du Colombier 	mntwalk,
11969ef1f84bSDavid du Colombier 	mntstat,
11979ef1f84bSDavid du Colombier 	mntopen,
11989ef1f84bSDavid du Colombier 	mntcreate,
11999ef1f84bSDavid du Colombier 	mntclose,
12009ef1f84bSDavid du Colombier 	mntread,
12019ef1f84bSDavid du Colombier 	devbread,
12029ef1f84bSDavid du Colombier 	mntwrite,
12039ef1f84bSDavid du Colombier 	devbwrite,
12049ef1f84bSDavid du Colombier 	mntremove,
12059ef1f84bSDavid du Colombier 	mntwstat,
12069ef1f84bSDavid du Colombier };
1207