xref: /plan9-contrib/sys/src/9/port/devmnt.c (revision ee4c62df6a71dfab7d1acfb429e15196ac8d7436)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
73e12c5d1SDavid du Colombier 
89a747e4fSDavid du Colombier /*
99a747e4fSDavid du Colombier  * References are managed as follows:
109a747e4fSDavid du Colombier  * The channel to the server - a network connection or pipe - has one
119a747e4fSDavid du Colombier  * reference for every Chan open on the server.  The server channel has
129a747e4fSDavid du Colombier  * c->mux set to the Mnt used for muxing control to that server.  Mnts
139a747e4fSDavid du Colombier  * have no reference count; they go away when c goes away.
149a747e4fSDavid du Colombier  * Each channel derived from the mount point has mchan set to c,
159a747e4fSDavid du Colombier  * and increfs/decrefs mchan to manage references on the server
169a747e4fSDavid du Colombier  * connection.
179a747e4fSDavid du Colombier  */
189a747e4fSDavid du Colombier 
19*ee4c62dfSDavid du Colombier #define MAXRPC (IOHDRSZ+16*1024)	/* maybe a larger size will be faster */
20*ee4c62dfSDavid du Colombier /* use a known-good common size for initial negotiation */
21*ee4c62dfSDavid du Colombier #define MAXCMNRPC (IOHDRSZ+8192)
229a747e4fSDavid du Colombier 
233e12c5d1SDavid du Colombier struct Mntrpc
243e12c5d1SDavid du Colombier {
257dd7cddfSDavid du Colombier 	Chan*	c;		/* Channel for whom we are working */
263e12c5d1SDavid du Colombier 	Mntrpc*	list;		/* Free/pending list */
273e12c5d1SDavid du Colombier 	Fcall	request;	/* Outgoing file system protocol message */
283e12c5d1SDavid du Colombier 	Fcall 	reply;		/* Incoming reply */
293e12c5d1SDavid du Colombier 	Mnt*	m;		/* Mount device during rpc */
303e12c5d1SDavid du Colombier 	Rendez	r;		/* Place to hang out */
319a747e4fSDavid du Colombier 	uchar*	rpc;		/* I/O Data buffer */
329a747e4fSDavid du Colombier 	uint	rpclen;		/* len of buffer */
339a747e4fSDavid du Colombier 	Block	*b;		/* reply blocks */
343e12c5d1SDavid du Colombier 	char	done;		/* Rpc completed */
357dd7cddfSDavid du Colombier 	uvlong	stime;		/* start time for mnt statistics */
367dd7cddfSDavid du Colombier 	ulong	reqlen;		/* request length for mnt statistics */
377dd7cddfSDavid du Colombier 	ulong	replen;		/* reply length for mnt statistics */
387dd7cddfSDavid du Colombier 	Mntrpc*	flushed;	/* message this one flushes */
393e12c5d1SDavid du Colombier };
403e12c5d1SDavid du Colombier 
41d9306527SDavid du Colombier enum
42d9306527SDavid du Colombier {
43d9306527SDavid du Colombier 	TAGSHIFT = 5,			/* ulong has to be 32 bits */
44d9306527SDavid du Colombier 	TAGMASK = (1<<TAGSHIFT)-1,
45d9306527SDavid du Colombier 	NMASK = (64*1024)>>TAGSHIFT,
46d9306527SDavid du Colombier };
47d9306527SDavid du Colombier 
483e12c5d1SDavid du Colombier struct Mntalloc
493e12c5d1SDavid du Colombier {
503e12c5d1SDavid du Colombier 	Lock;
517dd7cddfSDavid du Colombier 	Mnt*	list;		/* Mount devices in use */
523e12c5d1SDavid du Colombier 	Mnt*	mntfree;	/* Free list */
533e12c5d1SDavid du Colombier 	Mntrpc*	rpcfree;
547dd7cddfSDavid du Colombier 	int	nrpcfree;
557dd7cddfSDavid du Colombier 	int	nrpcused;
567dd7cddfSDavid du Colombier 	ulong	id;
57d9306527SDavid du Colombier 	ulong	tagmask[NMASK];
583e12c5d1SDavid du Colombier }mntalloc;
593e12c5d1SDavid du Colombier 
603e12c5d1SDavid du Colombier Mnt*	mntchk(Chan*);
613e12c5d1SDavid du Colombier void	mntdirfix(uchar*, Chan*);
629a747e4fSDavid du Colombier Mntrpc*	mntflushalloc(Mntrpc*, ulong);
637dd7cddfSDavid du Colombier void	mntflushfree(Mnt*, Mntrpc*);
643e12c5d1SDavid du Colombier void	mntfree(Mntrpc*);
653e12c5d1SDavid du Colombier void	mntgate(Mnt*);
663e12c5d1SDavid du Colombier void	mntpntfree(Mnt*);
673e12c5d1SDavid du Colombier void	mntqrm(Mnt*, Mntrpc*);
689a747e4fSDavid du Colombier Mntrpc*	mntralloc(Chan*, ulong);
697dd7cddfSDavid du Colombier long	mntrdwr(int, Chan*, void*, long, vlong);
709a747e4fSDavid du Colombier int	mntrpcread(Mnt*, Mntrpc*);
713e12c5d1SDavid du Colombier void	mountio(Mnt*, Mntrpc*);
723e12c5d1SDavid du Colombier void	mountmux(Mnt*, Mntrpc*);
733e12c5d1SDavid du Colombier void	mountrpc(Mnt*, Mntrpc*);
747dd7cddfSDavid du Colombier int	rpcattn(void*);
757dd7cddfSDavid du Colombier Chan*	mntchan(void);
76219b2ee8SDavid du Colombier 
779a747e4fSDavid du Colombier char	Esbadstat[] = "invalid directory entry received from server";
789a747e4fSDavid du Colombier char	Enoversion[] = "version not established for mount channel";
799a747e4fSDavid du Colombier 
803e12c5d1SDavid du Colombier 
81d9306527SDavid du Colombier void (*mntstats)(int, Chan*, uvlong, ulong);
823e12c5d1SDavid du Colombier 
837dd7cddfSDavid du Colombier static void
mntreset(void)843e12c5d1SDavid du Colombier mntreset(void)
853e12c5d1SDavid du Colombier {
863e12c5d1SDavid du Colombier 	mntalloc.id = 1;
87d9306527SDavid du Colombier 	mntalloc.tagmask[0] = 1;			/* don't allow 0 as a tag */
88d9306527SDavid du Colombier 	mntalloc.tagmask[NMASK-1] = 0x80000000UL;	/* don't allow NOTAG */
899a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
909a747e4fSDavid du Colombier 	fmtinstall('D', dirfmt);
91d9306527SDavid du Colombier /* We can't install %M since eipfmt does and is used in the kernel [sape] */
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier 	cinit();
943e12c5d1SDavid du Colombier }
953e12c5d1SDavid du Colombier 
969a747e4fSDavid du Colombier /*
979a747e4fSDavid du Colombier  * Version is not multiplexed: message sent only once per connection.
989a747e4fSDavid du Colombier  */
999a747e4fSDavid du Colombier long
mntversion(Chan * c,char * version,int msize,int returnlen)1009a747e4fSDavid du Colombier mntversion(Chan *c, char *version, int msize, int returnlen)
1013e12c5d1SDavid du Colombier {
1029a747e4fSDavid du Colombier 	Fcall f;
1039a747e4fSDavid du Colombier 	uchar *msg;
1043e12c5d1SDavid du Colombier 	Mnt *m;
1059a747e4fSDavid du Colombier 	char *v;
1069a747e4fSDavid du Colombier 	long k, l;
1079a747e4fSDavid du Colombier 	uvlong oo;
1089a747e4fSDavid du Colombier 	char buf[128];
1093e12c5d1SDavid du Colombier 
1109a747e4fSDavid du Colombier 	qlock(&c->umqlock);	/* make sure no one else does this until we've established ourselves */
1117dd7cddfSDavid du Colombier 	if(waserror()){
1129a747e4fSDavid du Colombier 		qunlock(&c->umqlock);
1137dd7cddfSDavid du Colombier 		nexterror();
1147dd7cddfSDavid du Colombier 	}
1159a747e4fSDavid du Colombier 
1169a747e4fSDavid du Colombier 	/* defaults */
1179a747e4fSDavid du Colombier 	if(msize == 0)
1189a747e4fSDavid du Colombier 		msize = MAXRPC;
1199a747e4fSDavid du Colombier 	if(msize > c->iounit && c->iounit != 0)
1209a747e4fSDavid du Colombier 		msize = c->iounit;
1219a747e4fSDavid du Colombier 	v = version;
1229a747e4fSDavid du Colombier 	if(v == nil || v[0] == '\0')
1239a747e4fSDavid du Colombier 		v = VERSION9P;
1249a747e4fSDavid du Colombier 
1259a747e4fSDavid du Colombier 	/* validity */
1269a747e4fSDavid du Colombier 	if(msize < 0)
1279a747e4fSDavid du Colombier 		error("bad iounit in version call");
1289a747e4fSDavid du Colombier 	if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
1299a747e4fSDavid du Colombier 		error("bad 9P version specification");
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier 	m = c->mux;
1329a747e4fSDavid du Colombier 
1339a747e4fSDavid du Colombier 	if(m != nil){
1349a747e4fSDavid du Colombier 		qunlock(&c->umqlock);
1357dd7cddfSDavid du Colombier 		poperror();
1369a747e4fSDavid du Colombier 
1379a747e4fSDavid du Colombier 		strecpy(buf, buf+sizeof buf, m->version);
1389a747e4fSDavid du Colombier 		k = strlen(buf);
1399a747e4fSDavid du Colombier 		if(strncmp(buf, v, k) != 0){
1409a747e4fSDavid du Colombier 			snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
1419a747e4fSDavid du Colombier 			error(buf);
1423e12c5d1SDavid du Colombier 		}
1439a747e4fSDavid du Colombier 		if(returnlen > 0){
1449a747e4fSDavid du Colombier 			if(returnlen < k)
1459a747e4fSDavid du Colombier 				error(Eshort);
1469a747e4fSDavid du Colombier 			memmove(version, buf, k);
1473e12c5d1SDavid du Colombier 		}
1489a747e4fSDavid du Colombier 		return k;
1493e12c5d1SDavid du Colombier 	}
150219b2ee8SDavid du Colombier 
1519a747e4fSDavid du Colombier 	f.type = Tversion;
1529a747e4fSDavid du Colombier 	f.tag = NOTAG;
1539a747e4fSDavid du Colombier 	f.msize = msize;
1549a747e4fSDavid du Colombier 	f.version = v;
155*ee4c62dfSDavid du Colombier 	msg = malloc(MAXCMNRPC);
1569a747e4fSDavid du Colombier 	if(msg == nil)
1579a747e4fSDavid du Colombier 		exhausted("version memory");
1589a747e4fSDavid du Colombier 	if(waserror()){
1599a747e4fSDavid du Colombier 		free(msg);
1609a747e4fSDavid du Colombier 		nexterror();
1619a747e4fSDavid du Colombier 	}
162*ee4c62dfSDavid du Colombier 	k = convS2M(&f, msg, MAXCMNRPC);
1639a747e4fSDavid du Colombier 	if(k == 0)
1649a747e4fSDavid du Colombier 		error("bad fversion conversion on send");
1659a747e4fSDavid du Colombier 
1669a747e4fSDavid du Colombier 	lock(c);
1679a747e4fSDavid du Colombier 	oo = c->offset;
1689a747e4fSDavid du Colombier 	c->offset += k;
1699a747e4fSDavid du Colombier 	unlock(c);
1709a747e4fSDavid du Colombier 
1719a747e4fSDavid du Colombier 	l = devtab[c->type]->write(c, msg, k, oo);
1729a747e4fSDavid du Colombier 
1739a747e4fSDavid du Colombier 	if(l < k){
1749a747e4fSDavid du Colombier 		lock(c);
1759a747e4fSDavid du Colombier 		c->offset -= k - l;
1769a747e4fSDavid du Colombier 		unlock(c);
1779a747e4fSDavid du Colombier 		error("short write in fversion");
1789a747e4fSDavid du Colombier 	}
1799a747e4fSDavid du Colombier 
1809a747e4fSDavid du Colombier 	/* message sent; receive and decode reply */
181*ee4c62dfSDavid du Colombier 	k = devtab[c->type]->read(c, msg, MAXCMNRPC, c->offset);
1829a747e4fSDavid du Colombier 	if(k <= 0)
1839a747e4fSDavid du Colombier 		error("EOF receiving fversion reply");
1849a747e4fSDavid du Colombier 
1859a747e4fSDavid du Colombier 	lock(c);
1869a747e4fSDavid du Colombier 	c->offset += k;
1879a747e4fSDavid du Colombier 	unlock(c);
1889a747e4fSDavid du Colombier 
1899a747e4fSDavid du Colombier 	l = convM2S(msg, k, &f);
1909a747e4fSDavid du Colombier 	if(l != k)
1919a747e4fSDavid du Colombier 		error("bad fversion conversion on reply");
1929a747e4fSDavid du Colombier 	if(f.type != Rversion){
1939a747e4fSDavid du Colombier 		if(f.type == Rerror)
1949a747e4fSDavid du Colombier 			error(f.ename);
1959a747e4fSDavid du Colombier 		error("unexpected reply type in fversion");
1969a747e4fSDavid du Colombier 	}
1979a747e4fSDavid du Colombier 	if(f.msize > msize)
1989a747e4fSDavid du Colombier 		error("server tries to increase msize in fversion");
1999a747e4fSDavid du Colombier 	if(f.msize<256 || f.msize>1024*1024)
2009a747e4fSDavid du Colombier 		error("nonsense value of msize in fversion");
2015fe11e25SDavid du Colombier 	k = strlen(f.version);
2025fe11e25SDavid du Colombier 	if(strncmp(f.version, v, k) != 0)
2039a747e4fSDavid du Colombier 		error("bad 9P version returned from server");
2049a747e4fSDavid du Colombier 
2059a747e4fSDavid du Colombier 	/* now build Mnt associated with this connection */
2069a747e4fSDavid du Colombier 	lock(&mntalloc);
2073e12c5d1SDavid du Colombier 	m = mntalloc.mntfree;
2083e12c5d1SDavid du Colombier 	if(m != 0)
2093e12c5d1SDavid du Colombier 		mntalloc.mntfree = m->list;
2103e12c5d1SDavid du Colombier 	else {
2113e12c5d1SDavid du Colombier 		m = malloc(sizeof(Mnt));
2123e12c5d1SDavid du Colombier 		if(m == 0) {
2133e12c5d1SDavid du Colombier 			unlock(&mntalloc);
2143e12c5d1SDavid du Colombier 			exhausted("mount devices");
2153e12c5d1SDavid du Colombier 		}
2163e12c5d1SDavid du Colombier 	}
2173e12c5d1SDavid du Colombier 	m->list = mntalloc.list;
2183e12c5d1SDavid du Colombier 	mntalloc.list = m;
2199a747e4fSDavid du Colombier 	m->version = nil;
2209a747e4fSDavid du Colombier 	kstrdup(&m->version, f.version);
2213e12c5d1SDavid du Colombier 	m->id = mntalloc.id++;
2229a747e4fSDavid du Colombier 	m->q = qopen(10*MAXRPC, 0, nil, nil);
2239a747e4fSDavid du Colombier 	m->msize = f.msize;
2243e12c5d1SDavid du Colombier 	unlock(&mntalloc);
2253e12c5d1SDavid du Colombier 
2265fe11e25SDavid du Colombier 	if(returnlen > 0){
2275fe11e25SDavid du Colombier 		if(returnlen < k)
2285fe11e25SDavid du Colombier 			error(Eshort);
2295fe11e25SDavid du Colombier 		memmove(version, f.version, k);
2305fe11e25SDavid du Colombier 	}
2315fe11e25SDavid du Colombier 
2329a747e4fSDavid du Colombier 	poperror();	/* msg */
2339a747e4fSDavid du Colombier 	free(msg);
2349a747e4fSDavid du Colombier 
2357dd7cddfSDavid du Colombier 	lock(m);
2363e12c5d1SDavid du Colombier 	m->queue = 0;
2373e12c5d1SDavid du Colombier 	m->rip = 0;
2389a747e4fSDavid du Colombier 
2399a747e4fSDavid du Colombier 	c->flag |= CMSG;
2409a747e4fSDavid du Colombier 	c->mux = m;
2413e12c5d1SDavid du Colombier 	m->c = c;
2423e12c5d1SDavid du Colombier 	unlock(m);
2433e12c5d1SDavid du Colombier 
2449a747e4fSDavid du Colombier 	poperror();	/* c */
2459a747e4fSDavid du Colombier 	qunlock(&c->umqlock);
2469a747e4fSDavid du Colombier 
2479a747e4fSDavid du Colombier 	return k;
2489a747e4fSDavid du Colombier }
2499a747e4fSDavid du Colombier 
2509a747e4fSDavid du Colombier Chan*
mntauth(Chan * c,char * spec)2519a747e4fSDavid du Colombier mntauth(Chan *c, char *spec)
2529a747e4fSDavid du Colombier {
2539a747e4fSDavid du Colombier 	Mnt *m;
2549a747e4fSDavid du Colombier 	Mntrpc *r;
2559a747e4fSDavid du Colombier 
2569a747e4fSDavid du Colombier 	m = c->mux;
2579a747e4fSDavid du Colombier 
2589a747e4fSDavid du Colombier 	if(m == nil){
2599a747e4fSDavid du Colombier 		mntversion(c, VERSION9P, MAXRPC, 0);
2609a747e4fSDavid du Colombier 		m = c->mux;
2619a747e4fSDavid du Colombier 		if(m == nil)
2629a747e4fSDavid du Colombier 			error(Enoversion);
2639a747e4fSDavid du Colombier 	}
2649a747e4fSDavid du Colombier 
2657dd7cddfSDavid du Colombier 	c = mntchan();
2663e12c5d1SDavid du Colombier 	if(waserror()) {
2677dd7cddfSDavid du Colombier 		/* Close must not be called since it will
2687dd7cddfSDavid du Colombier 		 * call mnt recursively
269219b2ee8SDavid du Colombier 		 */
2703e12c5d1SDavid du Colombier 		chanfree(c);
2713e12c5d1SDavid du Colombier 		nexterror();
2723e12c5d1SDavid du Colombier 	}
2733e12c5d1SDavid du Colombier 
2749a747e4fSDavid du Colombier 	r = mntralloc(0, m->msize);
2757dd7cddfSDavid du Colombier 
2769a747e4fSDavid du Colombier 	if(waserror()) {
2779a747e4fSDavid du Colombier 		mntfree(r);
2789a747e4fSDavid du Colombier 		nexterror();
2797dd7cddfSDavid du Colombier 	}
2807dd7cddfSDavid du Colombier 
2819a747e4fSDavid du Colombier 	r->request.type = Tauth;
2829a747e4fSDavid du Colombier 	r->request.afid = c->fid;
2839a747e4fSDavid du Colombier 	r->request.uname = up->user;
2849a747e4fSDavid du Colombier 	r->request.aname = spec;
2859a747e4fSDavid du Colombier 	mountrpc(m, r);
2869a747e4fSDavid du Colombier 
2879a747e4fSDavid du Colombier 	c->qid = r->reply.aqid;
2889a747e4fSDavid du Colombier 	c->mchan = m->c;
2899a747e4fSDavid du Colombier 	incref(m->c);
2909a747e4fSDavid du Colombier 	c->mqid = c->qid;
2919a747e4fSDavid du Colombier 	c->mode = ORDWR;
2929a747e4fSDavid du Colombier 
2939a747e4fSDavid du Colombier 	poperror();	/* r */
2949a747e4fSDavid du Colombier 	mntfree(r);
2959a747e4fSDavid du Colombier 
2969a747e4fSDavid du Colombier 	poperror();	/* c */
2979a747e4fSDavid du Colombier 
2989a747e4fSDavid du Colombier 	return c;
2999a747e4fSDavid du Colombier 
3009a747e4fSDavid du Colombier }
3019a747e4fSDavid du Colombier 
3029a747e4fSDavid du Colombier static Chan*
mntattach(char * muxattach)3039a747e4fSDavid du Colombier mntattach(char *muxattach)
3049a747e4fSDavid du Colombier {
3059a747e4fSDavid du Colombier 	Mnt *m;
3069a747e4fSDavid du Colombier 	Chan *c;
3079a747e4fSDavid du Colombier 	Mntrpc *r;
3089a747e4fSDavid du Colombier 	struct bogus{
3099a747e4fSDavid du Colombier 		Chan	*chan;
3109a747e4fSDavid du Colombier 		Chan	*authchan;
3119a747e4fSDavid du Colombier 		char	*spec;
3129a747e4fSDavid du Colombier 		int	flags;
3139a747e4fSDavid du Colombier 	}bogus;
3149a747e4fSDavid du Colombier 
3159a747e4fSDavid du Colombier 	bogus = *((struct bogus *)muxattach);
3169a747e4fSDavid du Colombier 	c = bogus.chan;
3179a747e4fSDavid du Colombier 
3189a747e4fSDavid du Colombier 	m = c->mux;
3199a747e4fSDavid du Colombier 
3209a747e4fSDavid du Colombier 	if(m == nil){
3219a747e4fSDavid du Colombier 		mntversion(c, nil, 0, 0);
3229a747e4fSDavid du Colombier 		m = c->mux;
3239a747e4fSDavid du Colombier 		if(m == nil)
3249a747e4fSDavid du Colombier 			error(Enoversion);
3259a747e4fSDavid du Colombier 	}
3269a747e4fSDavid du Colombier 
3279a747e4fSDavid du Colombier 	c = mntchan();
3289a747e4fSDavid du Colombier 	if(waserror()) {
3299a747e4fSDavid du Colombier 		/* Close must not be called since it will
3309a747e4fSDavid du Colombier 		 * call mnt recursively
3319a747e4fSDavid du Colombier 		 */
3329a747e4fSDavid du Colombier 		chanfree(c);
3339a747e4fSDavid du Colombier 		nexterror();
3349a747e4fSDavid du Colombier 	}
3359a747e4fSDavid du Colombier 
3369a747e4fSDavid du Colombier 	r = mntralloc(0, m->msize);
3379a747e4fSDavid du Colombier 
3389a747e4fSDavid du Colombier 	if(waserror()) {
3399a747e4fSDavid du Colombier 		mntfree(r);
3409a747e4fSDavid du Colombier 		nexterror();
3419a747e4fSDavid du Colombier 	}
3429a747e4fSDavid du Colombier 
3439a747e4fSDavid du Colombier 	r->request.type = Tattach;
3449a747e4fSDavid du Colombier 	r->request.fid = c->fid;
3459a747e4fSDavid du Colombier 	if(bogus.authchan == nil)
3469a747e4fSDavid du Colombier 		r->request.afid = NOFID;
3479a747e4fSDavid du Colombier 	else
3489a747e4fSDavid du Colombier 		r->request.afid = bogus.authchan->fid;
3499a747e4fSDavid du Colombier 	r->request.uname = up->user;
3509a747e4fSDavid du Colombier 	r->request.aname = bogus.spec;
3519a747e4fSDavid du Colombier 	mountrpc(m, r);
3529a747e4fSDavid du Colombier 
3539a747e4fSDavid du Colombier 	c->qid = r->reply.qid;
3549a747e4fSDavid du Colombier 	c->mchan = m->c;
3559a747e4fSDavid du Colombier 	incref(m->c);
3569a747e4fSDavid du Colombier 	c->mqid = c->qid;
3579a747e4fSDavid du Colombier 
3589a747e4fSDavid du Colombier 	poperror();	/* r */
3599a747e4fSDavid du Colombier 	mntfree(r);
3609a747e4fSDavid du Colombier 
3619a747e4fSDavid du Colombier 	poperror();	/* c */
3629a747e4fSDavid du Colombier 
3637dd7cddfSDavid du Colombier 	if(bogus.flags&MCACHE)
3647dd7cddfSDavid du Colombier 		c->flag |= CCACHE;
3657dd7cddfSDavid du Colombier 	return c;
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier Chan*
mntchan(void)3697dd7cddfSDavid du Colombier mntchan(void)
3707dd7cddfSDavid du Colombier {
3717dd7cddfSDavid du Colombier 	Chan *c;
3727dd7cddfSDavid du Colombier 
3737dd7cddfSDavid du Colombier 	c = devattach('M', 0);
3747dd7cddfSDavid du Colombier 	lock(&mntalloc);
3757dd7cddfSDavid du Colombier 	c->dev = mntalloc.id++;
3767dd7cddfSDavid du Colombier 	unlock(&mntalloc);
3777dd7cddfSDavid du Colombier 
3789a747e4fSDavid du Colombier 	if(c->mchan)
3799a747e4fSDavid du Colombier 		panic("mntchan non-zero %p", c->mchan);
3807dd7cddfSDavid du Colombier 	return c;
3817dd7cddfSDavid du Colombier }
3827dd7cddfSDavid du Colombier 
3839a747e4fSDavid du Colombier static Walkqid*
mntwalk(Chan * c,Chan * nc,char ** name,int nname)3849a747e4fSDavid du Colombier mntwalk(Chan *c, Chan *nc, char **name, int nname)
3857dd7cddfSDavid du Colombier {
3869a747e4fSDavid du Colombier 	int i, alloc;
3873e12c5d1SDavid du Colombier 	Mnt *m;
3883e12c5d1SDavid du Colombier 	Mntrpc *r;
3899a747e4fSDavid du Colombier 	Walkqid *wq;
3903e12c5d1SDavid du Colombier 
3919a747e4fSDavid du Colombier 	if(nc != nil)
3929a747e4fSDavid du Colombier 		print("mntwalk: nc != nil\n");
3939a747e4fSDavid du Colombier 	if(nname > MAXWELEM)
3949a747e4fSDavid du Colombier 		error("devmnt: too many name elements");
3959a747e4fSDavid du Colombier 	alloc = 0;
3969a747e4fSDavid du Colombier 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
3979a747e4fSDavid du Colombier 	if(waserror()){
3989a747e4fSDavid du Colombier 		if(alloc && wq->clone!=nil)
3999a747e4fSDavid du Colombier 			cclose(wq->clone);
4009a747e4fSDavid du Colombier 		free(wq);
4019a747e4fSDavid du Colombier 		return nil;
4029a747e4fSDavid du Colombier 	}
4039a747e4fSDavid du Colombier 
4049a747e4fSDavid du Colombier 	alloc = 0;
4053e12c5d1SDavid du Colombier 	m = mntchk(c);
4069a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
4079a747e4fSDavid du Colombier 	if(nc == nil){
4089a747e4fSDavid du Colombier 		nc = devclone(c);
4099a747e4fSDavid du Colombier 		/*
4109a747e4fSDavid du Colombier 		 * Until the other side accepts this fid, we can't mntclose it.
4119a747e4fSDavid du Colombier 		 * Therefore set type to 0 for now; rootclose is known to be safe.
4129a747e4fSDavid du Colombier 		 */
4139a747e4fSDavid du Colombier 		nc->type = 0;
4143e12c5d1SDavid du Colombier 		alloc = 1;
4153e12c5d1SDavid du Colombier 	}
4169a747e4fSDavid du Colombier 	wq->clone = nc;
4176bbfed0dSDavid du Colombier 	nc->flag |= c->flag&CCACHE;
4189a747e4fSDavid du Colombier 
4193e12c5d1SDavid du Colombier 	if(waserror()) {
4203e12c5d1SDavid du Colombier 		mntfree(r);
4213e12c5d1SDavid du Colombier 		nexterror();
4223e12c5d1SDavid du Colombier 	}
4233e12c5d1SDavid du Colombier 	r->request.type = Twalk;
4243e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
4259a747e4fSDavid du Colombier 	r->request.newfid = nc->fid;
4269a747e4fSDavid du Colombier 	r->request.nwname = nname;
4279a747e4fSDavid du Colombier 	memmove(r->request.wname, name, nname*sizeof(char*));
4289a747e4fSDavid du Colombier 
4293e12c5d1SDavid du Colombier 	mountrpc(m, r);
4303e12c5d1SDavid du Colombier 
4319a747e4fSDavid du Colombier 	if(r->reply.nwqid > nname)
4329a747e4fSDavid du Colombier 		error("too many QIDs returned by walk");
4339a747e4fSDavid du Colombier 	if(r->reply.nwqid < nname){
4349a747e4fSDavid du Colombier 		if(alloc)
4359a747e4fSDavid du Colombier 			cclose(nc);
4369a747e4fSDavid du Colombier 		wq->clone = nil;
4379a747e4fSDavid du Colombier 		if(r->reply.nwqid == 0){
4389a747e4fSDavid du Colombier 			free(wq);
4399a747e4fSDavid du Colombier 			wq = nil;
4409a747e4fSDavid du Colombier 			goto Return;
4419a747e4fSDavid du Colombier 		}
4423e12c5d1SDavid du Colombier 	}
4433e12c5d1SDavid du Colombier 
4449a747e4fSDavid du Colombier 	/* move new fid onto mnt device and update its qid */
4459a747e4fSDavid du Colombier 	if(wq->clone != nil){
4469a747e4fSDavid du Colombier 		if(wq->clone != c){
4479a747e4fSDavid du Colombier 			wq->clone->type = c->type;
4489a747e4fSDavid du Colombier 			wq->clone->mchan = c->mchan;
4499a747e4fSDavid du Colombier 			incref(c->mchan);
4509a747e4fSDavid du Colombier 		}
4519a747e4fSDavid du Colombier 		if(r->reply.nwqid > 0)
4529a747e4fSDavid du Colombier 			wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
4539a747e4fSDavid du Colombier 	}
4549a747e4fSDavid du Colombier 	wq->nqid = r->reply.nwqid;
4559a747e4fSDavid du Colombier 	for(i=0; i<wq->nqid; i++)
4569a747e4fSDavid du Colombier 		wq->qid[i] = r->reply.wqid[i];
4579a747e4fSDavid du Colombier 
4589a747e4fSDavid du Colombier     Return:
4599a747e4fSDavid du Colombier 	poperror();
4609a747e4fSDavid du Colombier 	mntfree(r);
4619a747e4fSDavid du Colombier 	poperror();
4629a747e4fSDavid du Colombier 	return wq;
4639a747e4fSDavid du Colombier }
4649a747e4fSDavid du Colombier 
4659a747e4fSDavid du Colombier static int
mntstat(Chan * c,uchar * dp,int n)4669a747e4fSDavid du Colombier mntstat(Chan *c, uchar *dp, int n)
4673e12c5d1SDavid du Colombier {
4683e12c5d1SDavid du Colombier 	Mnt *m;
4693e12c5d1SDavid du Colombier 	Mntrpc *r;
4703e12c5d1SDavid du Colombier 
4719a747e4fSDavid du Colombier 	if(n < BIT16SZ)
4729a747e4fSDavid du Colombier 		error(Eshortstat);
4733e12c5d1SDavid du Colombier 	m = mntchk(c);
4749a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
4753e12c5d1SDavid du Colombier 	if(waserror()) {
4763e12c5d1SDavid du Colombier 		mntfree(r);
4773e12c5d1SDavid du Colombier 		nexterror();
4783e12c5d1SDavid du Colombier 	}
4793e12c5d1SDavid du Colombier 	r->request.type = Tstat;
4803e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
4813e12c5d1SDavid du Colombier 	mountrpc(m, r);
4823e12c5d1SDavid du Colombier 
4839a747e4fSDavid du Colombier 	if(r->reply.nstat > n){
4849a747e4fSDavid du Colombier 		n = BIT16SZ;
485754a2748SDavid du Colombier 		PBIT16((uchar*)dp, r->reply.nstat-2);
4869a747e4fSDavid du Colombier 	}else{
4879a747e4fSDavid du Colombier 		n = r->reply.nstat;
4889a747e4fSDavid du Colombier 		memmove(dp, r->reply.stat, n);
4899a747e4fSDavid du Colombier 		validstat(dp, n);
4909a747e4fSDavid du Colombier 		mntdirfix(dp, c);
4919a747e4fSDavid du Colombier 	}
4923e12c5d1SDavid du Colombier 	poperror();
4933e12c5d1SDavid du Colombier 	mntfree(r);
4949a747e4fSDavid du Colombier 	return n;
4953e12c5d1SDavid du Colombier }
4963e12c5d1SDavid du Colombier 
4977dd7cddfSDavid du Colombier static Chan*
mntopencreate(int type,Chan * c,char * name,int omode,ulong perm)4989a747e4fSDavid du Colombier mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
4993e12c5d1SDavid du Colombier {
5003e12c5d1SDavid du Colombier 	Mnt *m;
5013e12c5d1SDavid du Colombier 	Mntrpc *r;
5023e12c5d1SDavid du Colombier 
5033e12c5d1SDavid du Colombier 	m = mntchk(c);
5049a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
5053e12c5d1SDavid du Colombier 	if(waserror()) {
5063e12c5d1SDavid du Colombier 		mntfree(r);
5073e12c5d1SDavid du Colombier 		nexterror();
5083e12c5d1SDavid du Colombier 	}
5099a747e4fSDavid du Colombier 	r->request.type = type;
5103e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
5113e12c5d1SDavid du Colombier 	r->request.mode = omode;
5129a747e4fSDavid du Colombier 	if(type == Tcreate){
5139a747e4fSDavid du Colombier 		r->request.perm = perm;
5149a747e4fSDavid du Colombier 		r->request.name = name;
5159a747e4fSDavid du Colombier 	}
5163e12c5d1SDavid du Colombier 	mountrpc(m, r);
5173e12c5d1SDavid du Colombier 
5183e12c5d1SDavid du Colombier 	c->qid = r->reply.qid;
5193e12c5d1SDavid du Colombier 	c->offset = 0;
5203e12c5d1SDavid du Colombier 	c->mode = openmode(omode);
5219a747e4fSDavid du Colombier 	c->iounit = r->reply.iounit;
5229a747e4fSDavid du Colombier 	if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
5239a747e4fSDavid du Colombier 		c->iounit = m->msize-IOHDRSZ;
5243e12c5d1SDavid du Colombier 	c->flag |= COPEN;
5253e12c5d1SDavid du Colombier 	poperror();
5263e12c5d1SDavid du Colombier 	mntfree(r);
5277dd7cddfSDavid du Colombier 
5287dd7cddfSDavid du Colombier 	if(c->flag & CCACHE)
5297dd7cddfSDavid du Colombier 		copen(c);
5307dd7cddfSDavid du Colombier 
5313e12c5d1SDavid du Colombier 	return c;
5323e12c5d1SDavid du Colombier }
5333e12c5d1SDavid du Colombier 
5349a747e4fSDavid du Colombier static Chan*
mntopen(Chan * c,int omode)5359a747e4fSDavid du Colombier mntopen(Chan *c, int omode)
5369a747e4fSDavid du Colombier {
5379a747e4fSDavid du Colombier 	return mntopencreate(Topen, c, nil, omode, 0);
5389a747e4fSDavid du Colombier }
5399a747e4fSDavid du Colombier 
5407dd7cddfSDavid du Colombier static void
mntcreate(Chan * c,char * name,int omode,ulong perm)5413e12c5d1SDavid du Colombier mntcreate(Chan *c, char *name, int omode, ulong perm)
5423e12c5d1SDavid du Colombier {
5439a747e4fSDavid du Colombier 	mntopencreate(Tcreate, c, name, omode, perm);
5443e12c5d1SDavid du Colombier }
5453e12c5d1SDavid du Colombier 
5467dd7cddfSDavid du Colombier static void
mntclunk(Chan * c,int t)5473e12c5d1SDavid du Colombier mntclunk(Chan *c, int t)
5483e12c5d1SDavid du Colombier {
5493e12c5d1SDavid du Colombier 	Mnt *m;
5503e12c5d1SDavid du Colombier 	Mntrpc *r;
5513e12c5d1SDavid du Colombier 
5523e12c5d1SDavid du Colombier 	m = mntchk(c);
5539a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
5543e12c5d1SDavid du Colombier 	if(waserror()){
5557dd7cddfSDavid du Colombier 		mntfree(r);
5563e12c5d1SDavid du Colombier 		nexterror();
5573e12c5d1SDavid du Colombier 	}
5583e12c5d1SDavid du Colombier 
5593e12c5d1SDavid du Colombier 	r->request.type = t;
5603e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
5613e12c5d1SDavid du Colombier 	mountrpc(m, r);
5627dd7cddfSDavid du Colombier 	mntfree(r);
5633e12c5d1SDavid du Colombier 	poperror();
5643e12c5d1SDavid du Colombier }
5653e12c5d1SDavid du Colombier 
5663e12c5d1SDavid du Colombier void
muxclose(Mnt * m)5679a747e4fSDavid du Colombier muxclose(Mnt *m)
5683e12c5d1SDavid du Colombier {
569219b2ee8SDavid du Colombier 	Mntrpc *q, *r;
5703e12c5d1SDavid du Colombier 
5713e12c5d1SDavid du Colombier 	for(q = m->queue; q; q = r) {
5723e12c5d1SDavid du Colombier 		r = q->list;
5733e12c5d1SDavid du Colombier 		mntfree(q);
5743e12c5d1SDavid du Colombier 	}
5753e12c5d1SDavid du Colombier 	m->id = 0;
5769a747e4fSDavid du Colombier 	free(m->version);
5779a747e4fSDavid du Colombier 	m->version = nil;
5783e12c5d1SDavid du Colombier 	mntpntfree(m);
5793e12c5d1SDavid du Colombier }
580219b2ee8SDavid du Colombier 
581219b2ee8SDavid du Colombier void
mntpntfree(Mnt * m)5823e12c5d1SDavid du Colombier mntpntfree(Mnt *m)
5833e12c5d1SDavid du Colombier {
5843e12c5d1SDavid du Colombier 	Mnt *f, **l;
5859a747e4fSDavid du Colombier 	Queue *q;
5863e12c5d1SDavid du Colombier 
5873e12c5d1SDavid du Colombier 	lock(&mntalloc);
5883e12c5d1SDavid du Colombier 	l = &mntalloc.list;
5893e12c5d1SDavid du Colombier 	for(f = *l; f; f = f->list) {
5903e12c5d1SDavid du Colombier 		if(f == m) {
5913e12c5d1SDavid du Colombier 			*l = m->list;
5923e12c5d1SDavid du Colombier 			break;
5933e12c5d1SDavid du Colombier 		}
5943e12c5d1SDavid du Colombier 		l = &f->list;
5953e12c5d1SDavid du Colombier 	}
5963e12c5d1SDavid du Colombier 	m->list = mntalloc.mntfree;
5973e12c5d1SDavid du Colombier 	mntalloc.mntfree = m;
5989a747e4fSDavid du Colombier 	q = m->q;
5993e12c5d1SDavid du Colombier 	unlock(&mntalloc);
6009a747e4fSDavid du Colombier 
6019a747e4fSDavid du Colombier 	qfree(q);
6023e12c5d1SDavid du Colombier }
6033e12c5d1SDavid du Colombier 
6047dd7cddfSDavid du Colombier static void
mntclose(Chan * c)6053e12c5d1SDavid du Colombier mntclose(Chan *c)
6063e12c5d1SDavid du Colombier {
6073e12c5d1SDavid du Colombier 	mntclunk(c, Tclunk);
6083e12c5d1SDavid du Colombier }
6093e12c5d1SDavid du Colombier 
6107dd7cddfSDavid du Colombier static void
mntremove(Chan * c)6113e12c5d1SDavid du Colombier mntremove(Chan *c)
6123e12c5d1SDavid du Colombier {
6133e12c5d1SDavid du Colombier 	mntclunk(c, Tremove);
6143e12c5d1SDavid du Colombier }
6153e12c5d1SDavid du Colombier 
6169a747e4fSDavid du Colombier static int
mntwstat(Chan * c,uchar * dp,int n)6179a747e4fSDavid du Colombier mntwstat(Chan *c, uchar *dp, int n)
6183e12c5d1SDavid du Colombier {
6193e12c5d1SDavid du Colombier 	Mnt *m;
6203e12c5d1SDavid du Colombier 	Mntrpc *r;
6213e12c5d1SDavid du Colombier 
6223e12c5d1SDavid du Colombier 	m = mntchk(c);
6239a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
6243e12c5d1SDavid du Colombier 	if(waserror()) {
6253e12c5d1SDavid du Colombier 		mntfree(r);
6263e12c5d1SDavid du Colombier 		nexterror();
6273e12c5d1SDavid du Colombier 	}
6283e12c5d1SDavid du Colombier 	r->request.type = Twstat;
6293e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
6309a747e4fSDavid du Colombier 	r->request.nstat = n;
6319a747e4fSDavid du Colombier 	r->request.stat = dp;
6323e12c5d1SDavid du Colombier 	mountrpc(m, r);
6333e12c5d1SDavid du Colombier 	poperror();
6343e12c5d1SDavid du Colombier 	mntfree(r);
6359a747e4fSDavid du Colombier 	return n;
6367dd7cddfSDavid du Colombier }
6377dd7cddfSDavid du Colombier 
6387dd7cddfSDavid du Colombier static long
mntread(Chan * c,void * buf,long n,vlong off)6397dd7cddfSDavid du Colombier mntread(Chan *c, void *buf, long n, vlong off)
6403e12c5d1SDavid du Colombier {
6413e12c5d1SDavid du Colombier 	uchar *p, *e;
6429a747e4fSDavid du Colombier 	int nc, cache, isdir, dirlen;
6433e12c5d1SDavid du Colombier 
6447dd7cddfSDavid du Colombier 	isdir = 0;
6457dd7cddfSDavid du Colombier 	cache = c->flag & CCACHE;
6469a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR) {
6477dd7cddfSDavid du Colombier 		cache = 0;
6487dd7cddfSDavid du Colombier 		isdir = 1;
6497dd7cddfSDavid du Colombier 	}
6507dd7cddfSDavid du Colombier 
6517dd7cddfSDavid du Colombier 	p = buf;
6527dd7cddfSDavid du Colombier 	if(cache) {
6537dd7cddfSDavid du Colombier 		nc = cread(c, buf, n, off);
6547dd7cddfSDavid du Colombier 		if(nc > 0) {
6557dd7cddfSDavid du Colombier 			n -= nc;
6567dd7cddfSDavid du Colombier 			if(n == 0)
6577dd7cddfSDavid du Colombier 				return nc;
6587dd7cddfSDavid du Colombier 			p += nc;
6597dd7cddfSDavid du Colombier 			off += nc;
6607dd7cddfSDavid du Colombier 		}
6617dd7cddfSDavid du Colombier 		n = mntrdwr(Tread, c, p, n, off);
6627dd7cddfSDavid du Colombier 		cupdate(c, p, n, off);
6637dd7cddfSDavid du Colombier 		return n + nc;
6647dd7cddfSDavid du Colombier 	}
6657dd7cddfSDavid du Colombier 
6667dd7cddfSDavid du Colombier 	n = mntrdwr(Tread, c, buf, n, off);
6677dd7cddfSDavid du Colombier 	if(isdir) {
6689a747e4fSDavid du Colombier 		for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
6699a747e4fSDavid du Colombier 			dirlen = BIT16SZ+GBIT16(p);
6709a747e4fSDavid du Colombier 			if(p+dirlen > e)
6719a747e4fSDavid du Colombier 				break;
6729a747e4fSDavid du Colombier 			validstat(p, dirlen);
6733e12c5d1SDavid du Colombier 			mntdirfix(p, c);
6747dd7cddfSDavid du Colombier 		}
6759a747e4fSDavid du Colombier 		if(p != e)
6769a747e4fSDavid du Colombier 			error(Esbadstat);
6773e12c5d1SDavid du Colombier 	}
6789a747e4fSDavid du Colombier 	return n;
6797dd7cddfSDavid du Colombier }
6807dd7cddfSDavid du Colombier 
6817dd7cddfSDavid du Colombier static long
mntwrite(Chan * c,void * buf,long n,vlong off)6827dd7cddfSDavid du Colombier mntwrite(Chan *c, void *buf, long n, vlong off)
6837dd7cddfSDavid du Colombier {
6847dd7cddfSDavid du Colombier 	return mntrdwr(Twrite, c, buf, n, off);
6853e12c5d1SDavid du Colombier }
6863e12c5d1SDavid du Colombier 
6873e12c5d1SDavid du Colombier long
mntrdwr(int type,Chan * c,void * buf,long n,vlong off)6887dd7cddfSDavid du Colombier mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
6897dd7cddfSDavid du Colombier {
6907dd7cddfSDavid du Colombier 	Mnt *m;
6917dd7cddfSDavid du Colombier  	Mntrpc *r;
6927dd7cddfSDavid du Colombier 	char *uba;
6937dd7cddfSDavid du Colombier 	int cache;
6947dd7cddfSDavid du Colombier 	ulong cnt, nr, nreq;
6957dd7cddfSDavid du Colombier 
6967dd7cddfSDavid du Colombier 	m = mntchk(c);
6977dd7cddfSDavid du Colombier 	uba = buf;
6987dd7cddfSDavid du Colombier 	cnt = 0;
6997dd7cddfSDavid du Colombier 	cache = c->flag & CCACHE;
7009a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
7017dd7cddfSDavid du Colombier 		cache = 0;
7027dd7cddfSDavid du Colombier 	for(;;) {
7039a747e4fSDavid du Colombier 		r = mntralloc(c, m->msize);
7047dd7cddfSDavid du Colombier 		if(waserror()) {
7057dd7cddfSDavid du Colombier 			mntfree(r);
7067dd7cddfSDavid du Colombier 			nexterror();
7077dd7cddfSDavid du Colombier 		}
7087dd7cddfSDavid du Colombier 		r->request.type = type;
7097dd7cddfSDavid du Colombier 		r->request.fid = c->fid;
7107dd7cddfSDavid du Colombier 		r->request.offset = off;
7117dd7cddfSDavid du Colombier 		r->request.data = uba;
7129a747e4fSDavid du Colombier 		nr = n;
7139a747e4fSDavid du Colombier 		if(nr > m->msize-IOHDRSZ)
7149a747e4fSDavid du Colombier 			nr = m->msize-IOHDRSZ;
7159a747e4fSDavid du Colombier 		r->request.count = nr;
7167dd7cddfSDavid du Colombier 		mountrpc(m, r);
7177dd7cddfSDavid du Colombier 		nreq = r->request.count;
7187dd7cddfSDavid du Colombier 		nr = r->reply.count;
7197dd7cddfSDavid du Colombier 		if(nr > nreq)
7207dd7cddfSDavid du Colombier 			nr = nreq;
7217dd7cddfSDavid du Colombier 
7227dd7cddfSDavid du Colombier 		if(type == Tread)
7239a747e4fSDavid du Colombier 			r->b = bl2mem((uchar*)uba, r->b, nr);
7247dd7cddfSDavid du Colombier 		else if(cache)
7257dd7cddfSDavid du Colombier 			cwrite(c, (uchar*)uba, nr, off);
7267dd7cddfSDavid du Colombier 
7277dd7cddfSDavid du Colombier 		poperror();
7287dd7cddfSDavid du Colombier 		mntfree(r);
7297dd7cddfSDavid du Colombier 		off += nr;
7303e12c5d1SDavid du Colombier 		uba += nr;
7313e12c5d1SDavid du Colombier 		cnt += nr;
732219b2ee8SDavid du Colombier 		n -= nr;
7337dd7cddfSDavid du Colombier 		if(nr != nreq || n == 0 || up->nnote)
7343e12c5d1SDavid du Colombier 			break;
7353e12c5d1SDavid du Colombier 	}
7363e12c5d1SDavid du Colombier 	return cnt;
7373e12c5d1SDavid du Colombier }
7383e12c5d1SDavid du Colombier 
7393e12c5d1SDavid du Colombier void
mountrpc(Mnt * m,Mntrpc * r)7403e12c5d1SDavid du Colombier mountrpc(Mnt *m, Mntrpc *r)
7413e12c5d1SDavid du Colombier {
7429a747e4fSDavid du Colombier 	char *sn, *cn;
7437dd7cddfSDavid du Colombier 	int t;
7447dd7cddfSDavid du Colombier 
7457dd7cddfSDavid du Colombier 	r->reply.tag = 0;
7467dd7cddfSDavid du Colombier 	r->reply.type = Tmax;	/* can't ever be a valid message type */
7473e12c5d1SDavid du Colombier 
7483e12c5d1SDavid du Colombier 	mountio(m, r);
7497dd7cddfSDavid du Colombier 
7507dd7cddfSDavid du Colombier 	t = r->reply.type;
7517dd7cddfSDavid du Colombier 	switch(t) {
7527dd7cddfSDavid du Colombier 	case Rerror:
7533e12c5d1SDavid du Colombier 		error(r->reply.ename);
7547dd7cddfSDavid du Colombier 	case Rflush:
7553e12c5d1SDavid du Colombier 		error(Eintr);
7567dd7cddfSDavid du Colombier 	default:
7577dd7cddfSDavid du Colombier 		if(t == r->request.type+1)
7587dd7cddfSDavid du Colombier 			break;
7599a747e4fSDavid du Colombier 		sn = "?";
7604afe124fSDavid du Colombier 		if(m->c->path != nil)
7614afe124fSDavid du Colombier 			sn = m->c->path->s;
7629a747e4fSDavid du Colombier 		cn = "?";
7634afe124fSDavid du Colombier 		if(r->c != nil && r->c->path != nil)
7644afe124fSDavid du Colombier 			cn = r->c->path->s;
765567483c8SDavid du Colombier 		print("mnt: proc %s %lud: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
7669a747e4fSDavid du Colombier 			up->text, up->pid, sn, cn,
7679a747e4fSDavid du Colombier 			r, r->request.tag, r->request.fid, r->request.type,
7689a747e4fSDavid du Colombier 			r->reply.type, r->reply.tag);
7693e12c5d1SDavid du Colombier 		error(Emountrpc);
7703e12c5d1SDavid du Colombier 	}
7713e12c5d1SDavid du Colombier }
7723e12c5d1SDavid du Colombier 
7733e12c5d1SDavid du Colombier void
mountio(Mnt * m,Mntrpc * r)7743e12c5d1SDavid du Colombier mountio(Mnt *m, Mntrpc *r)
7753e12c5d1SDavid du Colombier {
7763e12c5d1SDavid du Colombier 	int n;
7773e12c5d1SDavid du Colombier 
7787dd7cddfSDavid du Colombier 	while(waserror()) {
7797dd7cddfSDavid du Colombier 		if(m->rip == up)
7807dd7cddfSDavid du Colombier 			mntgate(m);
7819a747e4fSDavid du Colombier 		if(strcmp(up->errstr, Eintr) != 0){
7827dd7cddfSDavid du Colombier 			mntflushfree(m, r);
7837dd7cddfSDavid du Colombier 			nexterror();
7847dd7cddfSDavid du Colombier 		}
7859a747e4fSDavid du Colombier 		r = mntflushalloc(r, m->msize);
7867dd7cddfSDavid du Colombier 	}
7877dd7cddfSDavid du Colombier 
7883e12c5d1SDavid du Colombier 	lock(m);
7893e12c5d1SDavid du Colombier 	r->m = m;
7903e12c5d1SDavid du Colombier 	r->list = m->queue;
7913e12c5d1SDavid du Colombier 	m->queue = r;
7923e12c5d1SDavid du Colombier 	unlock(m);
7933e12c5d1SDavid du Colombier 
7943e12c5d1SDavid du Colombier 	/* Transmit a file system rpc */
7959a747e4fSDavid du Colombier 	if(m->msize == 0)
7969a747e4fSDavid du Colombier 		panic("msize");
7979a747e4fSDavid du Colombier 	n = convS2M(&r->request, r->rpc, m->msize);
7987dd7cddfSDavid du Colombier 	if(n < 0)
7997dd7cddfSDavid du Colombier 		panic("bad message type in mountio");
8007dd7cddfSDavid du Colombier 	if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
8017dd7cddfSDavid du Colombier 		error(Emountrpc);
8027dd7cddfSDavid du Colombier 	r->stime = fastticks(nil);
8037dd7cddfSDavid du Colombier 	r->reqlen = n;
8043e12c5d1SDavid du Colombier 
8053e12c5d1SDavid du Colombier 	/* Gate readers onto the mount point one at a time */
8063e12c5d1SDavid du Colombier 	for(;;) {
8073e12c5d1SDavid du Colombier 		lock(m);
8083e12c5d1SDavid du Colombier 		if(m->rip == 0)
8093e12c5d1SDavid du Colombier 			break;
8103e12c5d1SDavid du Colombier 		unlock(m);
8113e12c5d1SDavid du Colombier 		sleep(&r->r, rpcattn, r);
8127dd7cddfSDavid du Colombier 		if(r->done){
8133e12c5d1SDavid du Colombier 			poperror();
8147dd7cddfSDavid du Colombier 			mntflushfree(m, r);
8153e12c5d1SDavid du Colombier 			return;
8163e12c5d1SDavid du Colombier 		}
8177dd7cddfSDavid du Colombier 	}
8187dd7cddfSDavid du Colombier 	m->rip = up;
8193e12c5d1SDavid du Colombier 	unlock(m);
8203e12c5d1SDavid du Colombier 	while(r->done == 0) {
8219a747e4fSDavid du Colombier 		if(mntrpcread(m, r) < 0)
8229a747e4fSDavid du Colombier 			error(Emountrpc);
8233e12c5d1SDavid du Colombier 		mountmux(m, r);
8243e12c5d1SDavid du Colombier 	}
8253e12c5d1SDavid du Colombier 	mntgate(m);
8267dd7cddfSDavid du Colombier 	poperror();
8277dd7cddfSDavid du Colombier 	mntflushfree(m, r);
8283e12c5d1SDavid du Colombier }
8293e12c5d1SDavid du Colombier 
8306a9fc400SDavid du Colombier static int
doread(Mnt * m,int len)8316a9fc400SDavid du Colombier doread(Mnt *m, int len)
8326a9fc400SDavid du Colombier {
8336a9fc400SDavid du Colombier 	Block *b;
8346a9fc400SDavid du Colombier 
8356a9fc400SDavid du Colombier 	while(qlen(m->q) < len){
8366a9fc400SDavid du Colombier 		b = devtab[m->c->type]->bread(m->c, m->msize, 0);
8376a9fc400SDavid du Colombier 		if(b == nil)
8386a9fc400SDavid du Colombier 			return -1;
83918027f8cSDavid du Colombier 		if(blocklen(b) == 0){
8406a9fc400SDavid du Colombier 			freeblist(b);
8416a9fc400SDavid du Colombier 			return -1;
8426a9fc400SDavid du Colombier 		}
8436a9fc400SDavid du Colombier 		qaddlist(m->q, b);
8446a9fc400SDavid du Colombier 	}
8456a9fc400SDavid du Colombier 	return 0;
8466a9fc400SDavid du Colombier }
8476a9fc400SDavid du Colombier 
8489a747e4fSDavid du Colombier int
mntrpcread(Mnt * m,Mntrpc * r)8493e12c5d1SDavid du Colombier mntrpcread(Mnt *m, Mntrpc *r)
8503e12c5d1SDavid du Colombier {
8519a747e4fSDavid du Colombier 	int i, t, len, hlen;
8529a747e4fSDavid du Colombier 	Block *b, **l, *nb;
8533e12c5d1SDavid du Colombier 
8543e12c5d1SDavid du Colombier 	r->reply.type = 0;
8553e12c5d1SDavid du Colombier 	r->reply.tag = 0;
8563e12c5d1SDavid du Colombier 
8579a747e4fSDavid du Colombier 	/* read at least length, type, and tag and pullup to a single block */
8586a9fc400SDavid du Colombier 	if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
8599a747e4fSDavid du Colombier 		return -1;
8609a747e4fSDavid du Colombier 	nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
8619a747e4fSDavid du Colombier 
862ed8191acSDavid du Colombier 	/* read in the rest of the message, avoid ridiculous (for now) message sizes */
8636a9fc400SDavid du Colombier 	len = GBIT32(nb->rp);
8646a9fc400SDavid du Colombier 	if(len > m->msize){
8656a9fc400SDavid du Colombier 		qdiscard(m->q, qlen(m->q));
8669a747e4fSDavid du Colombier 		return -1;
8679a747e4fSDavid du Colombier 	}
8686a9fc400SDavid du Colombier 	if(doread(m, len) < 0)
8696a9fc400SDavid du Colombier 		return -1;
8709a747e4fSDavid du Colombier 
8719a747e4fSDavid du Colombier 	/* pullup the header (i.e. everything except data) */
8729a747e4fSDavid du Colombier 	t = nb->rp[BIT32SZ];
8739a747e4fSDavid du Colombier 	switch(t){
8749a747e4fSDavid du Colombier 	case Rread:
8759a747e4fSDavid du Colombier 		hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
8769a747e4fSDavid du Colombier 		break;
8779a747e4fSDavid du Colombier 	default:
8789a747e4fSDavid du Colombier 		hlen = len;
8799a747e4fSDavid du Colombier 		break;
8809a747e4fSDavid du Colombier 	}
8819a747e4fSDavid du Colombier 	nb = pullupqueue(m->q, hlen);
8829a747e4fSDavid du Colombier 
8839a747e4fSDavid du Colombier 	if(convM2S(nb->rp, len, &r->reply) <= 0){
8849a747e4fSDavid du Colombier 		/* bad message, dump it */
8859a747e4fSDavid du Colombier 		print("mntrpcread: convM2S failed\n");
8869a747e4fSDavid du Colombier 		qdiscard(m->q, len);
8879a747e4fSDavid du Colombier 		return -1;
8889a747e4fSDavid du Colombier 	}
8899a747e4fSDavid du Colombier 
8909a747e4fSDavid du Colombier 	/* hang the data off of the fcall struct */
8919a747e4fSDavid du Colombier 	l = &r->b;
8929a747e4fSDavid du Colombier 	*l = nil;
8939a747e4fSDavid du Colombier 	do {
8949a747e4fSDavid du Colombier 		b = qremove(m->q);
8959a747e4fSDavid du Colombier 		if(hlen > 0){
8969a747e4fSDavid du Colombier 			b->rp += hlen;
8979a747e4fSDavid du Colombier 			len -= hlen;
8989a747e4fSDavid du Colombier 			hlen = 0;
8999a747e4fSDavid du Colombier 		}
9009a747e4fSDavid du Colombier 		i = BLEN(b);
9019a747e4fSDavid du Colombier 		if(i <= len){
9029a747e4fSDavid du Colombier 			len -= i;
9039a747e4fSDavid du Colombier 			*l = b;
9049a747e4fSDavid du Colombier 			l = &(b->next);
9059a747e4fSDavid du Colombier 		} else {
9069a747e4fSDavid du Colombier 			/* split block and put unused bit back */
9079a747e4fSDavid du Colombier 			nb = allocb(i-len);
9089a747e4fSDavid du Colombier 			memmove(nb->wp, b->rp+len, i-len);
9099a747e4fSDavid du Colombier 			b->wp = b->rp+len;
9109a747e4fSDavid du Colombier 			nb->wp += i-len;
9119a747e4fSDavid du Colombier 			qputback(m->q, nb);
9129a747e4fSDavid du Colombier 			*l = b;
9139a747e4fSDavid du Colombier 			return 0;
9149a747e4fSDavid du Colombier 		}
9159a747e4fSDavid du Colombier 	}while(len > 0);
9169a747e4fSDavid du Colombier 
9179a747e4fSDavid du Colombier 	return 0;
9183e12c5d1SDavid du Colombier }
9193e12c5d1SDavid du Colombier 
9203e12c5d1SDavid du Colombier void
mntgate(Mnt * m)9213e12c5d1SDavid du Colombier mntgate(Mnt *m)
9223e12c5d1SDavid du Colombier {
9233e12c5d1SDavid du Colombier 	Mntrpc *q;
9243e12c5d1SDavid du Colombier 
9253e12c5d1SDavid du Colombier 	lock(m);
9263e12c5d1SDavid du Colombier 	m->rip = 0;
9277dd7cddfSDavid du Colombier 	for(q = m->queue; q; q = q->list) {
9287dd7cddfSDavid du Colombier 		if(q->done == 0)
9297dd7cddfSDavid du Colombier 		if(wakeup(&q->r))
9307dd7cddfSDavid du Colombier 			break;
9313e12c5d1SDavid du Colombier 	}
9323e12c5d1SDavid du Colombier 	unlock(m);
9333e12c5d1SDavid du Colombier }
9343e12c5d1SDavid du Colombier 
9353e12c5d1SDavid du Colombier void
mountmux(Mnt * m,Mntrpc * r)9363e12c5d1SDavid du Colombier mountmux(Mnt *m, Mntrpc *r)
9373e12c5d1SDavid du Colombier {
9383e12c5d1SDavid du Colombier 	Mntrpc **l, *q;
9393e12c5d1SDavid du Colombier 
9403e12c5d1SDavid du Colombier 	lock(m);
9413e12c5d1SDavid du Colombier 	l = &m->queue;
9423e12c5d1SDavid du Colombier 	for(q = *l; q; q = q->list) {
9437dd7cddfSDavid du Colombier 		/* look for a reply to a message */
9447dd7cddfSDavid du Colombier 		if(q->request.tag == r->reply.tag) {
9453e12c5d1SDavid du Colombier 			*l = q->list;
9467dd7cddfSDavid du Colombier 			if(q != r) {
9477dd7cddfSDavid du Colombier 				/*
9487dd7cddfSDavid du Colombier 				 * Completed someone else.
9497dd7cddfSDavid du Colombier 				 * Trade pointers to receive buffer.
9507dd7cddfSDavid du Colombier 				 */
9517dd7cddfSDavid du Colombier 				q->reply = r->reply;
9529a747e4fSDavid du Colombier 				q->b = r->b;
9539a747e4fSDavid du Colombier 				r->b = nil;
9547dd7cddfSDavid du Colombier 			}
9553e12c5d1SDavid du Colombier 			q->done = 1;
9567dd7cddfSDavid du Colombier 			unlock(m);
9577dd7cddfSDavid du Colombier 			if(mntstats != nil)
9587dd7cddfSDavid du Colombier 				(*mntstats)(q->request.type,
9597dd7cddfSDavid du Colombier 					m->c, q->stime,
9607dd7cddfSDavid du Colombier 					q->reqlen + r->replen);
9617dd7cddfSDavid du Colombier 			if(q != r)
9623e12c5d1SDavid du Colombier 				wakeup(&q->r);
9633e12c5d1SDavid du Colombier 			return;
9643e12c5d1SDavid du Colombier 		}
9653e12c5d1SDavid du Colombier 		l = &q->list;
9663e12c5d1SDavid du Colombier 	}
9673e12c5d1SDavid du Colombier 	unlock(m);
9689a747e4fSDavid du Colombier 	print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
9693e12c5d1SDavid du Colombier }
9703e12c5d1SDavid du Colombier 
9717dd7cddfSDavid du Colombier /*
9727dd7cddfSDavid du Colombier  * Create a new flush request and chain the previous
9737dd7cddfSDavid du Colombier  * requests from it
9747dd7cddfSDavid du Colombier  */
9757dd7cddfSDavid du Colombier Mntrpc*
mntflushalloc(Mntrpc * r,ulong iounit)9769a747e4fSDavid du Colombier mntflushalloc(Mntrpc *r, ulong iounit)
9773e12c5d1SDavid du Colombier {
9787dd7cddfSDavid du Colombier 	Mntrpc *fr;
9793e12c5d1SDavid du Colombier 
9809a747e4fSDavid du Colombier 	fr = mntralloc(0, iounit);
9813e12c5d1SDavid du Colombier 
9827dd7cddfSDavid du Colombier 	fr->request.type = Tflush;
9837dd7cddfSDavid du Colombier 	if(r->request.type == Tflush)
9847dd7cddfSDavid du Colombier 		fr->request.oldtag = r->request.oldtag;
9857dd7cddfSDavid du Colombier 	else
9867dd7cddfSDavid du Colombier 		fr->request.oldtag = r->request.tag;
9877dd7cddfSDavid du Colombier 	fr->flushed = r;
9883e12c5d1SDavid du Colombier 
9897dd7cddfSDavid du Colombier 	return fr;
9903e12c5d1SDavid du Colombier }
9917dd7cddfSDavid du Colombier 
9927dd7cddfSDavid du Colombier /*
9937dd7cddfSDavid du Colombier  *  Free a chain of flushes.  Remove each unanswered
9947dd7cddfSDavid du Colombier  *  flush and the original message from the unanswered
9957dd7cddfSDavid du Colombier  *  request queue.  Mark the original message as done
9967dd7cddfSDavid du Colombier  *  and if it hasn't been answered set the reply to to
9977dd7cddfSDavid du Colombier  *  Rflush.
9987dd7cddfSDavid du Colombier  */
9997dd7cddfSDavid du Colombier void
mntflushfree(Mnt * m,Mntrpc * r)10007dd7cddfSDavid du Colombier mntflushfree(Mnt *m, Mntrpc *r)
10017dd7cddfSDavid du Colombier {
10027dd7cddfSDavid du Colombier 	Mntrpc *fr;
10037dd7cddfSDavid du Colombier 
10047dd7cddfSDavid du Colombier 	while(r){
10057dd7cddfSDavid du Colombier 		fr = r->flushed;
10067dd7cddfSDavid du Colombier 		if(!r->done){
10077dd7cddfSDavid du Colombier 			r->reply.type = Rflush;
10087dd7cddfSDavid du Colombier 			mntqrm(m, r);
10097dd7cddfSDavid du Colombier 		}
10107dd7cddfSDavid du Colombier 		if(fr)
10117dd7cddfSDavid du Colombier 			mntfree(r);
10127dd7cddfSDavid du Colombier 		r = fr;
10137dd7cddfSDavid du Colombier 	}
10143e12c5d1SDavid du Colombier }
10153e12c5d1SDavid du Colombier 
1016d9306527SDavid du Colombier int
alloctag(void)1017d9306527SDavid du Colombier alloctag(void)
1018d9306527SDavid du Colombier {
1019d9306527SDavid du Colombier 	int i, j;
1020d9306527SDavid du Colombier 	ulong v;
1021d9306527SDavid du Colombier 
1022d9306527SDavid du Colombier 	for(i = 0; i < NMASK; i++){
1023d9306527SDavid du Colombier 		v = mntalloc.tagmask[i];
1024d9306527SDavid du Colombier 		if(v == ~0UL)
1025d9306527SDavid du Colombier 			continue;
1026d9306527SDavid du Colombier 		for(j = 0; j < 1<<TAGSHIFT; j++)
1027d9306527SDavid du Colombier 			if((v & (1<<j)) == 0){
1028d9306527SDavid du Colombier 				mntalloc.tagmask[i] |= 1<<j;
1029d9306527SDavid du Colombier 				return (i<<TAGSHIFT) + j;
1030d9306527SDavid du Colombier 			}
1031d9306527SDavid du Colombier 	}
1032d9306527SDavid du Colombier 	panic("no friggin tags left");
1033d9306527SDavid du Colombier 	return NOTAG;
1034d9306527SDavid du Colombier }
1035d9306527SDavid du Colombier 
1036d9306527SDavid du Colombier void
freetag(int t)1037d9306527SDavid du Colombier freetag(int t)
1038d9306527SDavid du Colombier {
1039d9306527SDavid du Colombier 	mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1040d9306527SDavid du Colombier }
1041d9306527SDavid du Colombier 
10423e12c5d1SDavid du Colombier Mntrpc*
mntralloc(Chan * c,ulong msize)10439a747e4fSDavid du Colombier mntralloc(Chan *c, ulong msize)
10443e12c5d1SDavid du Colombier {
10453e12c5d1SDavid du Colombier 	Mntrpc *new;
10463e12c5d1SDavid du Colombier 
10473e12c5d1SDavid du Colombier 	lock(&mntalloc);
10483e12c5d1SDavid du Colombier 	new = mntalloc.rpcfree;
10497dd7cddfSDavid du Colombier 	if(new == nil){
10507dd7cddfSDavid du Colombier 		new = malloc(sizeof(Mntrpc));
10517dd7cddfSDavid du Colombier 		if(new == nil) {
10527dd7cddfSDavid du Colombier 			unlock(&mntalloc);
10537dd7cddfSDavid du Colombier 			exhausted("mount rpc header");
10547dd7cddfSDavid du Colombier 		}
10557dd7cddfSDavid du Colombier 		/*
10567dd7cddfSDavid du Colombier 		 * The header is split from the data buffer as
10577dd7cddfSDavid du Colombier 		 * mountmux may swap the buffer with another header.
10587dd7cddfSDavid du Colombier 		 */
10599a747e4fSDavid du Colombier 		new->rpc = mallocz(msize, 0);
10607dd7cddfSDavid du Colombier 		if(new->rpc == nil){
10617dd7cddfSDavid du Colombier 			free(new);
10623e12c5d1SDavid du Colombier 			unlock(&mntalloc);
10633e12c5d1SDavid du Colombier 			exhausted("mount rpc buffer");
10643e12c5d1SDavid du Colombier 		}
10659a747e4fSDavid du Colombier 		new->rpclen = msize;
1066d9306527SDavid du Colombier 		new->request.tag = alloctag();
10673e12c5d1SDavid du Colombier 	}
10687dd7cddfSDavid du Colombier 	else {
10697dd7cddfSDavid du Colombier 		mntalloc.rpcfree = new->list;
10707dd7cddfSDavid du Colombier 		mntalloc.nrpcfree--;
10719a747e4fSDavid du Colombier 		if(new->rpclen < msize){
10729a747e4fSDavid du Colombier 			free(new->rpc);
10739a747e4fSDavid du Colombier 			new->rpc = mallocz(msize, 0);
10749a747e4fSDavid du Colombier 			if(new->rpc == nil){
10759a747e4fSDavid du Colombier 				free(new);
10769a747e4fSDavid du Colombier 				mntalloc.nrpcused--;
10779a747e4fSDavid du Colombier 				unlock(&mntalloc);
10789a747e4fSDavid du Colombier 				exhausted("mount rpc buffer");
10799a747e4fSDavid du Colombier 			}
10809a747e4fSDavid du Colombier 			new->rpclen = msize;
10819a747e4fSDavid du Colombier 		}
10827dd7cddfSDavid du Colombier 	}
10837dd7cddfSDavid du Colombier 	mntalloc.nrpcused++;
10843e12c5d1SDavid du Colombier 	unlock(&mntalloc);
10857dd7cddfSDavid du Colombier 	new->c = c;
10863e12c5d1SDavid du Colombier 	new->done = 0;
10877dd7cddfSDavid du Colombier 	new->flushed = nil;
10889a747e4fSDavid du Colombier 	new->b = nil;
10893e12c5d1SDavid du Colombier 	return new;
10903e12c5d1SDavid du Colombier }
10913e12c5d1SDavid du Colombier 
10923e12c5d1SDavid du Colombier void
mntfree(Mntrpc * r)10933e12c5d1SDavid du Colombier mntfree(Mntrpc *r)
10943e12c5d1SDavid du Colombier {
10959a747e4fSDavid du Colombier 	if(r->b != nil)
10969a747e4fSDavid du Colombier 		freeblist(r->b);
10973e12c5d1SDavid du Colombier 	lock(&mntalloc);
10987dd7cddfSDavid du Colombier 	if(mntalloc.nrpcfree >= 10){
10997dd7cddfSDavid du Colombier 		free(r->rpc);
1100d9306527SDavid du Colombier 		freetag(r->request.tag);
1101a23bc242SDavid du Colombier 		free(r);
11027dd7cddfSDavid du Colombier 	}
11037dd7cddfSDavid du Colombier 	else{
11043e12c5d1SDavid du Colombier 		r->list = mntalloc.rpcfree;
11053e12c5d1SDavid du Colombier 		mntalloc.rpcfree = r;
11067dd7cddfSDavid du Colombier 		mntalloc.nrpcfree++;
11077dd7cddfSDavid du Colombier 	}
11087dd7cddfSDavid du Colombier 	mntalloc.nrpcused--;
11093e12c5d1SDavid du Colombier 	unlock(&mntalloc);
11103e12c5d1SDavid du Colombier }
11113e12c5d1SDavid du Colombier 
11123e12c5d1SDavid du Colombier void
mntqrm(Mnt * m,Mntrpc * r)11133e12c5d1SDavid du Colombier mntqrm(Mnt *m, Mntrpc *r)
11143e12c5d1SDavid du Colombier {
11153e12c5d1SDavid du Colombier 	Mntrpc **l, *f;
11163e12c5d1SDavid du Colombier 
11173e12c5d1SDavid du Colombier 	lock(m);
11183e12c5d1SDavid du Colombier 	r->done = 1;
11193e12c5d1SDavid du Colombier 
11203e12c5d1SDavid du Colombier 	l = &m->queue;
11213e12c5d1SDavid du Colombier 	for(f = *l; f; f = f->list) {
11223e12c5d1SDavid du Colombier 		if(f == r) {
11233e12c5d1SDavid du Colombier 			*l = r->list;
11243e12c5d1SDavid du Colombier 			break;
11253e12c5d1SDavid du Colombier 		}
11263e12c5d1SDavid du Colombier 		l = &f->list;
11273e12c5d1SDavid du Colombier 	}
11283e12c5d1SDavid du Colombier 	unlock(m);
11293e12c5d1SDavid du Colombier }
11303e12c5d1SDavid du Colombier 
11313e12c5d1SDavid du Colombier Mnt*
mntchk(Chan * c)11323e12c5d1SDavid du Colombier mntchk(Chan *c)
11333e12c5d1SDavid du Colombier {
11343e12c5d1SDavid du Colombier 	Mnt *m;
11353e12c5d1SDavid du Colombier 
11369a747e4fSDavid du Colombier 	/* This routine is mostly vestiges of prior lives; now it's just sanity checking */
11379a747e4fSDavid du Colombier 
11389a747e4fSDavid du Colombier 	if(c->mchan == nil)
11394afe124fSDavid du Colombier 		panic("mntchk 1: nil mchan c %s\n", chanpath(c));
11409a747e4fSDavid du Colombier 
11419a747e4fSDavid du Colombier 	m = c->mchan->mux;
11429a747e4fSDavid du Colombier 
11439a747e4fSDavid du Colombier 	if(m == nil)
11444afe124fSDavid du Colombier 		print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
11457dd7cddfSDavid du Colombier 
11467dd7cddfSDavid du Colombier 	/*
11478cd4f5a6SDavid du Colombier 	 * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
11487dd7cddfSDavid du Colombier 	 */
11497dd7cddfSDavid du Colombier 	if(m->id == 0 || m->id >= c->dev)
11509a747e4fSDavid du Colombier 		panic("mntchk 3: can't happen");
11517dd7cddfSDavid du Colombier 
11523e12c5d1SDavid du Colombier 	return m;
11533e12c5d1SDavid du Colombier }
11543e12c5d1SDavid du Colombier 
11559a747e4fSDavid du Colombier /*
11569a747e4fSDavid du Colombier  * Rewrite channel type and dev for in-flight data to
11579a747e4fSDavid du Colombier  * reflect local values.  These entries are known to be
11589a747e4fSDavid du Colombier  * the first two in the Dir encoding after the count.
11599a747e4fSDavid du Colombier  */
11603e12c5d1SDavid du Colombier void
mntdirfix(uchar * dirbuf,Chan * c)11613e12c5d1SDavid du Colombier mntdirfix(uchar *dirbuf, Chan *c)
11623e12c5d1SDavid du Colombier {
11639a747e4fSDavid du Colombier 	uint r;
11647dd7cddfSDavid du Colombier 
11657dd7cddfSDavid du Colombier 	r = devtab[c->type]->dc;
11669a747e4fSDavid du Colombier 	dirbuf += BIT16SZ;	/* skip count */
11679a747e4fSDavid du Colombier 	PBIT16(dirbuf, r);
11689a747e4fSDavid du Colombier 	dirbuf += BIT16SZ;
11699a747e4fSDavid du Colombier 	PBIT32(dirbuf, c->dev);
11703e12c5d1SDavid du Colombier }
11713e12c5d1SDavid du Colombier 
11723e12c5d1SDavid du Colombier int
rpcattn(void * v)11737dd7cddfSDavid du Colombier rpcattn(void *v)
11743e12c5d1SDavid du Colombier {
11757dd7cddfSDavid du Colombier 	Mntrpc *r;
11767dd7cddfSDavid du Colombier 
11777dd7cddfSDavid du Colombier 	r = v;
11783e12c5d1SDavid du Colombier 	return r->done || r->m->rip == 0;
11793e12c5d1SDavid du Colombier }
11807dd7cddfSDavid du Colombier 
11817dd7cddfSDavid du Colombier Dev mntdevtab = {
11827dd7cddfSDavid du Colombier 	'M',
11837dd7cddfSDavid du Colombier 	"mnt",
11847dd7cddfSDavid du Colombier 
11857dd7cddfSDavid du Colombier 	mntreset,
11867dd7cddfSDavid du Colombier 	devinit,
11879a747e4fSDavid du Colombier 	devshutdown,
11887dd7cddfSDavid du Colombier 	mntattach,
11897dd7cddfSDavid du Colombier 	mntwalk,
11907dd7cddfSDavid du Colombier 	mntstat,
11917dd7cddfSDavid du Colombier 	mntopen,
11927dd7cddfSDavid du Colombier 	mntcreate,
11937dd7cddfSDavid du Colombier 	mntclose,
11947dd7cddfSDavid du Colombier 	mntread,
11957dd7cddfSDavid du Colombier 	devbread,
11967dd7cddfSDavid du Colombier 	mntwrite,
11977dd7cddfSDavid du Colombier 	devbwrite,
11987dd7cddfSDavid du Colombier 	mntremove,
11997dd7cddfSDavid du Colombier 	mntwstat,
12007dd7cddfSDavid du Colombier };
1201