xref: /plan9/sys/src/9/port/devmnt.c (revision 6bbfed0d85c6d7248503ef0614d0f1e40438b735)
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 
199a747e4fSDavid du Colombier #define MAXRPC (IOHDRSZ+8192)
209a747e4fSDavid du Colombier 
213e12c5d1SDavid du Colombier struct Mntrpc
223e12c5d1SDavid du Colombier {
237dd7cddfSDavid du Colombier 	Chan*	c;		/* Channel for whom we are working */
243e12c5d1SDavid du Colombier 	Mntrpc*	list;		/* Free/pending list */
253e12c5d1SDavid du Colombier 	Fcall	request;	/* Outgoing file system protocol message */
263e12c5d1SDavid du Colombier 	Fcall 	reply;		/* Incoming reply */
273e12c5d1SDavid du Colombier 	Mnt*	m;		/* Mount device during rpc */
283e12c5d1SDavid du Colombier 	Rendez	r;		/* Place to hang out */
299a747e4fSDavid du Colombier 	uchar*	rpc;		/* I/O Data buffer */
309a747e4fSDavid du Colombier 	uint	rpclen;		/* len of buffer */
319a747e4fSDavid du Colombier 	Block	*b;		/* reply blocks */
323e12c5d1SDavid du Colombier 	char	done;		/* Rpc completed */
337dd7cddfSDavid du Colombier 	uvlong	stime;		/* start time for mnt statistics */
347dd7cddfSDavid du Colombier 	ulong	reqlen;		/* request length for mnt statistics */
357dd7cddfSDavid du Colombier 	ulong	replen;		/* reply length for mnt statistics */
367dd7cddfSDavid du Colombier 	Mntrpc*	flushed;	/* message this one flushes */
373e12c5d1SDavid du Colombier };
383e12c5d1SDavid du Colombier 
39d9306527SDavid du Colombier enum
40d9306527SDavid du Colombier {
41d9306527SDavid du Colombier 	TAGSHIFT = 5,			/* ulong has to be 32 bits */
42d9306527SDavid du Colombier 	TAGMASK = (1<<TAGSHIFT)-1,
43d9306527SDavid du Colombier 	NMASK = (64*1024)>>TAGSHIFT,
44d9306527SDavid du Colombier };
45d9306527SDavid du Colombier 
463e12c5d1SDavid du Colombier struct Mntalloc
473e12c5d1SDavid du Colombier {
483e12c5d1SDavid du Colombier 	Lock;
497dd7cddfSDavid du Colombier 	Mnt*	list;		/* Mount devices in use */
503e12c5d1SDavid du Colombier 	Mnt*	mntfree;	/* Free list */
513e12c5d1SDavid du Colombier 	Mntrpc*	rpcfree;
527dd7cddfSDavid du Colombier 	int	nrpcfree;
537dd7cddfSDavid du Colombier 	int	nrpcused;
547dd7cddfSDavid du Colombier 	ulong	id;
55d9306527SDavid du Colombier 	ulong	tagmask[NMASK];
563e12c5d1SDavid du Colombier }mntalloc;
573e12c5d1SDavid du Colombier 
583e12c5d1SDavid du Colombier Mnt*	mntchk(Chan*);
593e12c5d1SDavid du Colombier void	mntdirfix(uchar*, Chan*);
609a747e4fSDavid du Colombier Mntrpc*	mntflushalloc(Mntrpc*, ulong);
617dd7cddfSDavid du Colombier void	mntflushfree(Mnt*, Mntrpc*);
623e12c5d1SDavid du Colombier void	mntfree(Mntrpc*);
633e12c5d1SDavid du Colombier void	mntgate(Mnt*);
643e12c5d1SDavid du Colombier void	mntpntfree(Mnt*);
653e12c5d1SDavid du Colombier void	mntqrm(Mnt*, Mntrpc*);
669a747e4fSDavid du Colombier Mntrpc*	mntralloc(Chan*, ulong);
677dd7cddfSDavid du Colombier long	mntrdwr(int, Chan*, void*, long, vlong);
689a747e4fSDavid du Colombier int	mntrpcread(Mnt*, Mntrpc*);
693e12c5d1SDavid du Colombier void	mountio(Mnt*, Mntrpc*);
703e12c5d1SDavid du Colombier void	mountmux(Mnt*, Mntrpc*);
713e12c5d1SDavid du Colombier void	mountrpc(Mnt*, Mntrpc*);
727dd7cddfSDavid du Colombier int	rpcattn(void*);
737dd7cddfSDavid du Colombier Chan*	mntchan(void);
74219b2ee8SDavid du Colombier 
759a747e4fSDavid du Colombier char	Esbadstat[] = "invalid directory entry received from server";
769a747e4fSDavid du Colombier char	Enoversion[] = "version not established for mount channel";
779a747e4fSDavid du Colombier 
783e12c5d1SDavid du Colombier 
79d9306527SDavid du Colombier void (*mntstats)(int, Chan*, uvlong, ulong);
803e12c5d1SDavid du Colombier 
817dd7cddfSDavid du Colombier static void
mntreset(void)823e12c5d1SDavid du Colombier mntreset(void)
833e12c5d1SDavid du Colombier {
843e12c5d1SDavid du Colombier 	mntalloc.id = 1;
85d9306527SDavid du Colombier 	mntalloc.tagmask[0] = 1;			/* don't allow 0 as a tag */
86d9306527SDavid du Colombier 	mntalloc.tagmask[NMASK-1] = 0x80000000UL;	/* don't allow NOTAG */
879a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
889a747e4fSDavid du Colombier 	fmtinstall('D', dirfmt);
89d9306527SDavid du Colombier /* We can't install %M since eipfmt does and is used in the kernel [sape] */
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier 	cinit();
923e12c5d1SDavid du Colombier }
933e12c5d1SDavid du Colombier 
949a747e4fSDavid du Colombier /*
959a747e4fSDavid du Colombier  * Version is not multiplexed: message sent only once per connection.
969a747e4fSDavid du Colombier  */
979a747e4fSDavid du Colombier long
mntversion(Chan * c,char * version,int msize,int returnlen)989a747e4fSDavid du Colombier mntversion(Chan *c, char *version, int msize, int returnlen)
993e12c5d1SDavid du Colombier {
1009a747e4fSDavid du Colombier 	Fcall f;
1019a747e4fSDavid du Colombier 	uchar *msg;
1023e12c5d1SDavid du Colombier 	Mnt *m;
1039a747e4fSDavid du Colombier 	char *v;
1049a747e4fSDavid du Colombier 	long k, l;
1059a747e4fSDavid du Colombier 	uvlong oo;
1069a747e4fSDavid du Colombier 	char buf[128];
1073e12c5d1SDavid du Colombier 
1089a747e4fSDavid du Colombier 	qlock(&c->umqlock);	/* make sure no one else does this until we've established ourselves */
1097dd7cddfSDavid du Colombier 	if(waserror()){
1109a747e4fSDavid du Colombier 		qunlock(&c->umqlock);
1117dd7cddfSDavid du Colombier 		nexterror();
1127dd7cddfSDavid du Colombier 	}
1139a747e4fSDavid du Colombier 
1149a747e4fSDavid du Colombier 	/* defaults */
1159a747e4fSDavid du Colombier 	if(msize == 0)
1169a747e4fSDavid du Colombier 		msize = MAXRPC;
1179a747e4fSDavid du Colombier 	if(msize > c->iounit && c->iounit != 0)
1189a747e4fSDavid du Colombier 		msize = c->iounit;
1199a747e4fSDavid du Colombier 	v = version;
1209a747e4fSDavid du Colombier 	if(v == nil || v[0] == '\0')
1219a747e4fSDavid du Colombier 		v = VERSION9P;
1229a747e4fSDavid du Colombier 
1239a747e4fSDavid du Colombier 	/* validity */
1249a747e4fSDavid du Colombier 	if(msize < 0)
1259a747e4fSDavid du Colombier 		error("bad iounit in version call");
1269a747e4fSDavid du Colombier 	if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
1279a747e4fSDavid du Colombier 		error("bad 9P version specification");
1289a747e4fSDavid du Colombier 
1299a747e4fSDavid du Colombier 	m = c->mux;
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier 	if(m != nil){
1329a747e4fSDavid du Colombier 		qunlock(&c->umqlock);
1337dd7cddfSDavid du Colombier 		poperror();
1349a747e4fSDavid du Colombier 
1359a747e4fSDavid du Colombier 		strecpy(buf, buf+sizeof buf, m->version);
1369a747e4fSDavid du Colombier 		k = strlen(buf);
1379a747e4fSDavid du Colombier 		if(strncmp(buf, v, k) != 0){
1389a747e4fSDavid du Colombier 			snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
1399a747e4fSDavid du Colombier 			error(buf);
1403e12c5d1SDavid du Colombier 		}
1419a747e4fSDavid du Colombier 		if(returnlen > 0){
1429a747e4fSDavid du Colombier 			if(returnlen < k)
1439a747e4fSDavid du Colombier 				error(Eshort);
1449a747e4fSDavid du Colombier 			memmove(version, buf, k);
1453e12c5d1SDavid du Colombier 		}
1469a747e4fSDavid du Colombier 		return k;
1473e12c5d1SDavid du Colombier 	}
148219b2ee8SDavid du Colombier 
1499a747e4fSDavid du Colombier 	f.type = Tversion;
1509a747e4fSDavid du Colombier 	f.tag = NOTAG;
1519a747e4fSDavid du Colombier 	f.msize = msize;
1529a747e4fSDavid du Colombier 	f.version = v;
1539a747e4fSDavid du Colombier 	msg = malloc(8192+IOHDRSZ);
1549a747e4fSDavid du Colombier 	if(msg == nil)
1559a747e4fSDavid du Colombier 		exhausted("version memory");
1569a747e4fSDavid du Colombier 	if(waserror()){
1579a747e4fSDavid du Colombier 		free(msg);
1589a747e4fSDavid du Colombier 		nexterror();
1599a747e4fSDavid du Colombier 	}
1609a747e4fSDavid du Colombier 	k = convS2M(&f, msg, 8192+IOHDRSZ);
1619a747e4fSDavid du Colombier 	if(k == 0)
1629a747e4fSDavid du Colombier 		error("bad fversion conversion on send");
1639a747e4fSDavid du Colombier 
1649a747e4fSDavid du Colombier 	lock(c);
1659a747e4fSDavid du Colombier 	oo = c->offset;
1669a747e4fSDavid du Colombier 	c->offset += k;
1679a747e4fSDavid du Colombier 	unlock(c);
1689a747e4fSDavid du Colombier 
1699a747e4fSDavid du Colombier 	l = devtab[c->type]->write(c, msg, k, oo);
1709a747e4fSDavid du Colombier 
1719a747e4fSDavid du Colombier 	if(l < k){
1729a747e4fSDavid du Colombier 		lock(c);
1739a747e4fSDavid du Colombier 		c->offset -= k - l;
1749a747e4fSDavid du Colombier 		unlock(c);
1759a747e4fSDavid du Colombier 		error("short write in fversion");
1769a747e4fSDavid du Colombier 	}
1779a747e4fSDavid du Colombier 
1789a747e4fSDavid du Colombier 	/* message sent; receive and decode reply */
1799a747e4fSDavid du Colombier 	k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
1809a747e4fSDavid du Colombier 	if(k <= 0)
1819a747e4fSDavid du Colombier 		error("EOF receiving fversion reply");
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	lock(c);
1849a747e4fSDavid du Colombier 	c->offset += k;
1859a747e4fSDavid du Colombier 	unlock(c);
1869a747e4fSDavid du Colombier 
1879a747e4fSDavid du Colombier 	l = convM2S(msg, k, &f);
1889a747e4fSDavid du Colombier 	if(l != k)
1899a747e4fSDavid du Colombier 		error("bad fversion conversion on reply");
1909a747e4fSDavid du Colombier 	if(f.type != Rversion){
1919a747e4fSDavid du Colombier 		if(f.type == Rerror)
1929a747e4fSDavid du Colombier 			error(f.ename);
1939a747e4fSDavid du Colombier 		error("unexpected reply type in fversion");
1949a747e4fSDavid du Colombier 	}
1959a747e4fSDavid du Colombier 	if(f.msize > msize)
1969a747e4fSDavid du Colombier 		error("server tries to increase msize in fversion");
1979a747e4fSDavid du Colombier 	if(f.msize<256 || f.msize>1024*1024)
1989a747e4fSDavid du Colombier 		error("nonsense value of msize in fversion");
1995fe11e25SDavid du Colombier 	k = strlen(f.version);
2005fe11e25SDavid du Colombier 	if(strncmp(f.version, v, k) != 0)
2019a747e4fSDavid du Colombier 		error("bad 9P version returned from server");
2029a747e4fSDavid du Colombier 
2039a747e4fSDavid du Colombier 	/* now build Mnt associated with this connection */
2049a747e4fSDavid du Colombier 	lock(&mntalloc);
2053e12c5d1SDavid du Colombier 	m = mntalloc.mntfree;
2063e12c5d1SDavid du Colombier 	if(m != 0)
2073e12c5d1SDavid du Colombier 		mntalloc.mntfree = m->list;
2083e12c5d1SDavid du Colombier 	else {
2093e12c5d1SDavid du Colombier 		m = malloc(sizeof(Mnt));
2103e12c5d1SDavid du Colombier 		if(m == 0) {
2113e12c5d1SDavid du Colombier 			unlock(&mntalloc);
2123e12c5d1SDavid du Colombier 			exhausted("mount devices");
2133e12c5d1SDavid du Colombier 		}
2143e12c5d1SDavid du Colombier 	}
2153e12c5d1SDavid du Colombier 	m->list = mntalloc.list;
2163e12c5d1SDavid du Colombier 	mntalloc.list = m;
2179a747e4fSDavid du Colombier 	m->version = nil;
2189a747e4fSDavid du Colombier 	kstrdup(&m->version, f.version);
2193e12c5d1SDavid du Colombier 	m->id = mntalloc.id++;
2209a747e4fSDavid du Colombier 	m->q = qopen(10*MAXRPC, 0, nil, nil);
2219a747e4fSDavid du Colombier 	m->msize = f.msize;
2223e12c5d1SDavid du Colombier 	unlock(&mntalloc);
2233e12c5d1SDavid du Colombier 
2245fe11e25SDavid du Colombier 	if(returnlen > 0){
2255fe11e25SDavid du Colombier 		if(returnlen < k)
2265fe11e25SDavid du Colombier 			error(Eshort);
2275fe11e25SDavid du Colombier 		memmove(version, f.version, k);
2285fe11e25SDavid du Colombier 	}
2295fe11e25SDavid du Colombier 
2309a747e4fSDavid du Colombier 	poperror();	/* msg */
2319a747e4fSDavid du Colombier 	free(msg);
2329a747e4fSDavid du Colombier 
2337dd7cddfSDavid du Colombier 	lock(m);
2343e12c5d1SDavid du Colombier 	m->queue = 0;
2353e12c5d1SDavid du Colombier 	m->rip = 0;
2369a747e4fSDavid du Colombier 
2379a747e4fSDavid du Colombier 	c->flag |= CMSG;
2389a747e4fSDavid du Colombier 	c->mux = m;
2393e12c5d1SDavid du Colombier 	m->c = c;
2403e12c5d1SDavid du Colombier 	unlock(m);
2413e12c5d1SDavid du Colombier 
2429a747e4fSDavid du Colombier 	poperror();	/* c */
2439a747e4fSDavid du Colombier 	qunlock(&c->umqlock);
2449a747e4fSDavid du Colombier 
2459a747e4fSDavid du Colombier 	return k;
2469a747e4fSDavid du Colombier }
2479a747e4fSDavid du Colombier 
2489a747e4fSDavid du Colombier Chan*
mntauth(Chan * c,char * spec)2499a747e4fSDavid du Colombier mntauth(Chan *c, char *spec)
2509a747e4fSDavid du Colombier {
2519a747e4fSDavid du Colombier 	Mnt *m;
2529a747e4fSDavid du Colombier 	Mntrpc *r;
2539a747e4fSDavid du Colombier 
2549a747e4fSDavid du Colombier 	m = c->mux;
2559a747e4fSDavid du Colombier 
2569a747e4fSDavid du Colombier 	if(m == nil){
2579a747e4fSDavid du Colombier 		mntversion(c, VERSION9P, MAXRPC, 0);
2589a747e4fSDavid du Colombier 		m = c->mux;
2599a747e4fSDavid du Colombier 		if(m == nil)
2609a747e4fSDavid du Colombier 			error(Enoversion);
2619a747e4fSDavid du Colombier 	}
2629a747e4fSDavid du Colombier 
2637dd7cddfSDavid du Colombier 	c = mntchan();
2643e12c5d1SDavid du Colombier 	if(waserror()) {
2657dd7cddfSDavid du Colombier 		/* Close must not be called since it will
2667dd7cddfSDavid du Colombier 		 * call mnt recursively
267219b2ee8SDavid du Colombier 		 */
2683e12c5d1SDavid du Colombier 		chanfree(c);
2693e12c5d1SDavid du Colombier 		nexterror();
2703e12c5d1SDavid du Colombier 	}
2713e12c5d1SDavid du Colombier 
2729a747e4fSDavid du Colombier 	r = mntralloc(0, m->msize);
2737dd7cddfSDavid du Colombier 
2749a747e4fSDavid du Colombier 	if(waserror()) {
2759a747e4fSDavid du Colombier 		mntfree(r);
2769a747e4fSDavid du Colombier 		nexterror();
2777dd7cddfSDavid du Colombier 	}
2787dd7cddfSDavid du Colombier 
2799a747e4fSDavid du Colombier 	r->request.type = Tauth;
2809a747e4fSDavid du Colombier 	r->request.afid = c->fid;
2819a747e4fSDavid du Colombier 	r->request.uname = up->user;
2829a747e4fSDavid du Colombier 	r->request.aname = spec;
2839a747e4fSDavid du Colombier 	mountrpc(m, r);
2849a747e4fSDavid du Colombier 
2859a747e4fSDavid du Colombier 	c->qid = r->reply.aqid;
2869a747e4fSDavid du Colombier 	c->mchan = m->c;
2879a747e4fSDavid du Colombier 	incref(m->c);
2889a747e4fSDavid du Colombier 	c->mqid = c->qid;
2899a747e4fSDavid du Colombier 	c->mode = ORDWR;
2909a747e4fSDavid du Colombier 
2919a747e4fSDavid du Colombier 	poperror();	/* r */
2929a747e4fSDavid du Colombier 	mntfree(r);
2939a747e4fSDavid du Colombier 
2949a747e4fSDavid du Colombier 	poperror();	/* c */
2959a747e4fSDavid du Colombier 
2969a747e4fSDavid du Colombier 	return c;
2979a747e4fSDavid du Colombier 
2989a747e4fSDavid du Colombier }
2999a747e4fSDavid du Colombier 
3009a747e4fSDavid du Colombier static Chan*
mntattach(char * muxattach)3019a747e4fSDavid du Colombier mntattach(char *muxattach)
3029a747e4fSDavid du Colombier {
3039a747e4fSDavid du Colombier 	Mnt *m;
3049a747e4fSDavid du Colombier 	Chan *c;
3059a747e4fSDavid du Colombier 	Mntrpc *r;
3069a747e4fSDavid du Colombier 	struct bogus{
3079a747e4fSDavid du Colombier 		Chan	*chan;
3089a747e4fSDavid du Colombier 		Chan	*authchan;
3099a747e4fSDavid du Colombier 		char	*spec;
3109a747e4fSDavid du Colombier 		int	flags;
3119a747e4fSDavid du Colombier 	}bogus;
3129a747e4fSDavid du Colombier 
3139a747e4fSDavid du Colombier 	bogus = *((struct bogus *)muxattach);
3149a747e4fSDavid du Colombier 	c = bogus.chan;
3159a747e4fSDavid du Colombier 
3169a747e4fSDavid du Colombier 	m = c->mux;
3179a747e4fSDavid du Colombier 
3189a747e4fSDavid du Colombier 	if(m == nil){
3199a747e4fSDavid du Colombier 		mntversion(c, nil, 0, 0);
3209a747e4fSDavid du Colombier 		m = c->mux;
3219a747e4fSDavid du Colombier 		if(m == nil)
3229a747e4fSDavid du Colombier 			error(Enoversion);
3239a747e4fSDavid du Colombier 	}
3249a747e4fSDavid du Colombier 
3259a747e4fSDavid du Colombier 	c = mntchan();
3269a747e4fSDavid du Colombier 	if(waserror()) {
3279a747e4fSDavid du Colombier 		/* Close must not be called since it will
3289a747e4fSDavid du Colombier 		 * call mnt recursively
3299a747e4fSDavid du Colombier 		 */
3309a747e4fSDavid du Colombier 		chanfree(c);
3319a747e4fSDavid du Colombier 		nexterror();
3329a747e4fSDavid du Colombier 	}
3339a747e4fSDavid du Colombier 
3349a747e4fSDavid du Colombier 	r = mntralloc(0, m->msize);
3359a747e4fSDavid du Colombier 
3369a747e4fSDavid du Colombier 	if(waserror()) {
3379a747e4fSDavid du Colombier 		mntfree(r);
3389a747e4fSDavid du Colombier 		nexterror();
3399a747e4fSDavid du Colombier 	}
3409a747e4fSDavid du Colombier 
3419a747e4fSDavid du Colombier 	r->request.type = Tattach;
3429a747e4fSDavid du Colombier 	r->request.fid = c->fid;
3439a747e4fSDavid du Colombier 	if(bogus.authchan == nil)
3449a747e4fSDavid du Colombier 		r->request.afid = NOFID;
3459a747e4fSDavid du Colombier 	else
3469a747e4fSDavid du Colombier 		r->request.afid = bogus.authchan->fid;
3479a747e4fSDavid du Colombier 	r->request.uname = up->user;
3489a747e4fSDavid du Colombier 	r->request.aname = bogus.spec;
3499a747e4fSDavid du Colombier 	mountrpc(m, r);
3509a747e4fSDavid du Colombier 
3519a747e4fSDavid du Colombier 	c->qid = r->reply.qid;
3529a747e4fSDavid du Colombier 	c->mchan = m->c;
3539a747e4fSDavid du Colombier 	incref(m->c);
3549a747e4fSDavid du Colombier 	c->mqid = c->qid;
3559a747e4fSDavid du Colombier 
3569a747e4fSDavid du Colombier 	poperror();	/* r */
3579a747e4fSDavid du Colombier 	mntfree(r);
3589a747e4fSDavid du Colombier 
3599a747e4fSDavid du Colombier 	poperror();	/* c */
3609a747e4fSDavid du Colombier 
3617dd7cddfSDavid du Colombier 	if(bogus.flags&MCACHE)
3627dd7cddfSDavid du Colombier 		c->flag |= CCACHE;
3637dd7cddfSDavid du Colombier 	return c;
3647dd7cddfSDavid du Colombier }
3657dd7cddfSDavid du Colombier 
3667dd7cddfSDavid du Colombier Chan*
mntchan(void)3677dd7cddfSDavid du Colombier mntchan(void)
3687dd7cddfSDavid du Colombier {
3697dd7cddfSDavid du Colombier 	Chan *c;
3707dd7cddfSDavid du Colombier 
3717dd7cddfSDavid du Colombier 	c = devattach('M', 0);
3727dd7cddfSDavid du Colombier 	lock(&mntalloc);
3737dd7cddfSDavid du Colombier 	c->dev = mntalloc.id++;
3747dd7cddfSDavid du Colombier 	unlock(&mntalloc);
3757dd7cddfSDavid du Colombier 
3769a747e4fSDavid du Colombier 	if(c->mchan)
3779a747e4fSDavid du Colombier 		panic("mntchan non-zero %p", c->mchan);
3787dd7cddfSDavid du Colombier 	return c;
3797dd7cddfSDavid du Colombier }
3807dd7cddfSDavid du Colombier 
3819a747e4fSDavid du Colombier static Walkqid*
mntwalk(Chan * c,Chan * nc,char ** name,int nname)3829a747e4fSDavid du Colombier mntwalk(Chan *c, Chan *nc, char **name, int nname)
3837dd7cddfSDavid du Colombier {
3849a747e4fSDavid du Colombier 	int i, alloc;
3853e12c5d1SDavid du Colombier 	Mnt *m;
3863e12c5d1SDavid du Colombier 	Mntrpc *r;
3879a747e4fSDavid du Colombier 	Walkqid *wq;
3883e12c5d1SDavid du Colombier 
3899a747e4fSDavid du Colombier 	if(nc != nil)
3909a747e4fSDavid du Colombier 		print("mntwalk: nc != nil\n");
3919a747e4fSDavid du Colombier 	if(nname > MAXWELEM)
3929a747e4fSDavid du Colombier 		error("devmnt: too many name elements");
3939a747e4fSDavid du Colombier 	alloc = 0;
3949a747e4fSDavid du Colombier 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
3959a747e4fSDavid du Colombier 	if(waserror()){
3969a747e4fSDavid du Colombier 		if(alloc && wq->clone!=nil)
3979a747e4fSDavid du Colombier 			cclose(wq->clone);
3989a747e4fSDavid du Colombier 		free(wq);
3999a747e4fSDavid du Colombier 		return nil;
4009a747e4fSDavid du Colombier 	}
4019a747e4fSDavid du Colombier 
4029a747e4fSDavid du Colombier 	alloc = 0;
4033e12c5d1SDavid du Colombier 	m = mntchk(c);
4049a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
4059a747e4fSDavid du Colombier 	if(nc == nil){
4069a747e4fSDavid du Colombier 		nc = devclone(c);
4079a747e4fSDavid du Colombier 		/*
4089a747e4fSDavid du Colombier 		 * Until the other side accepts this fid, we can't mntclose it.
4099a747e4fSDavid du Colombier 		 * Therefore set type to 0 for now; rootclose is known to be safe.
4109a747e4fSDavid du Colombier 		 */
4119a747e4fSDavid du Colombier 		nc->type = 0;
4123e12c5d1SDavid du Colombier 		alloc = 1;
4133e12c5d1SDavid du Colombier 	}
4149a747e4fSDavid du Colombier 	wq->clone = nc;
415*6bbfed0dSDavid du Colombier 	nc->flag |= c->flag&CCACHE;
4169a747e4fSDavid du Colombier 
4173e12c5d1SDavid du Colombier 	if(waserror()) {
4183e12c5d1SDavid du Colombier 		mntfree(r);
4193e12c5d1SDavid du Colombier 		nexterror();
4203e12c5d1SDavid du Colombier 	}
4213e12c5d1SDavid du Colombier 	r->request.type = Twalk;
4223e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
4239a747e4fSDavid du Colombier 	r->request.newfid = nc->fid;
4249a747e4fSDavid du Colombier 	r->request.nwname = nname;
4259a747e4fSDavid du Colombier 	memmove(r->request.wname, name, nname*sizeof(char*));
4269a747e4fSDavid du Colombier 
4273e12c5d1SDavid du Colombier 	mountrpc(m, r);
4283e12c5d1SDavid du Colombier 
4299a747e4fSDavid du Colombier 	if(r->reply.nwqid > nname)
4309a747e4fSDavid du Colombier 		error("too many QIDs returned by walk");
4319a747e4fSDavid du Colombier 	if(r->reply.nwqid < nname){
4329a747e4fSDavid du Colombier 		if(alloc)
4339a747e4fSDavid du Colombier 			cclose(nc);
4349a747e4fSDavid du Colombier 		wq->clone = nil;
4359a747e4fSDavid du Colombier 		if(r->reply.nwqid == 0){
4369a747e4fSDavid du Colombier 			free(wq);
4379a747e4fSDavid du Colombier 			wq = nil;
4389a747e4fSDavid du Colombier 			goto Return;
4399a747e4fSDavid du Colombier 		}
4403e12c5d1SDavid du Colombier 	}
4413e12c5d1SDavid du Colombier 
4429a747e4fSDavid du Colombier 	/* move new fid onto mnt device and update its qid */
4439a747e4fSDavid du Colombier 	if(wq->clone != nil){
4449a747e4fSDavid du Colombier 		if(wq->clone != c){
4459a747e4fSDavid du Colombier 			wq->clone->type = c->type;
4469a747e4fSDavid du Colombier 			wq->clone->mchan = c->mchan;
4479a747e4fSDavid du Colombier 			incref(c->mchan);
4489a747e4fSDavid du Colombier 		}
4499a747e4fSDavid du Colombier 		if(r->reply.nwqid > 0)
4509a747e4fSDavid du Colombier 			wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
4519a747e4fSDavid du Colombier 	}
4529a747e4fSDavid du Colombier 	wq->nqid = r->reply.nwqid;
4539a747e4fSDavid du Colombier 	for(i=0; i<wq->nqid; i++)
4549a747e4fSDavid du Colombier 		wq->qid[i] = r->reply.wqid[i];
4559a747e4fSDavid du Colombier 
4569a747e4fSDavid du Colombier     Return:
4579a747e4fSDavid du Colombier 	poperror();
4589a747e4fSDavid du Colombier 	mntfree(r);
4599a747e4fSDavid du Colombier 	poperror();
4609a747e4fSDavid du Colombier 	return wq;
4619a747e4fSDavid du Colombier }
4629a747e4fSDavid du Colombier 
4639a747e4fSDavid du Colombier static int
mntstat(Chan * c,uchar * dp,int n)4649a747e4fSDavid du Colombier mntstat(Chan *c, uchar *dp, int n)
4653e12c5d1SDavid du Colombier {
4663e12c5d1SDavid du Colombier 	Mnt *m;
4673e12c5d1SDavid du Colombier 	Mntrpc *r;
4683e12c5d1SDavid du Colombier 
4699a747e4fSDavid du Colombier 	if(n < BIT16SZ)
4709a747e4fSDavid du Colombier 		error(Eshortstat);
4713e12c5d1SDavid du Colombier 	m = mntchk(c);
4729a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
4733e12c5d1SDavid du Colombier 	if(waserror()) {
4743e12c5d1SDavid du Colombier 		mntfree(r);
4753e12c5d1SDavid du Colombier 		nexterror();
4763e12c5d1SDavid du Colombier 	}
4773e12c5d1SDavid du Colombier 	r->request.type = Tstat;
4783e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
4793e12c5d1SDavid du Colombier 	mountrpc(m, r);
4803e12c5d1SDavid du Colombier 
4819a747e4fSDavid du Colombier 	if(r->reply.nstat > n){
4829a747e4fSDavid du Colombier 		n = BIT16SZ;
483754a2748SDavid du Colombier 		PBIT16((uchar*)dp, r->reply.nstat-2);
4849a747e4fSDavid du Colombier 	}else{
4859a747e4fSDavid du Colombier 		n = r->reply.nstat;
4869a747e4fSDavid du Colombier 		memmove(dp, r->reply.stat, n);
4879a747e4fSDavid du Colombier 		validstat(dp, n);
4889a747e4fSDavid du Colombier 		mntdirfix(dp, c);
4899a747e4fSDavid du Colombier 	}
4903e12c5d1SDavid du Colombier 	poperror();
4913e12c5d1SDavid du Colombier 	mntfree(r);
4929a747e4fSDavid du Colombier 	return n;
4933e12c5d1SDavid du Colombier }
4943e12c5d1SDavid du Colombier 
4957dd7cddfSDavid du Colombier static Chan*
mntopencreate(int type,Chan * c,char * name,int omode,ulong perm)4969a747e4fSDavid du Colombier mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
4973e12c5d1SDavid du Colombier {
4983e12c5d1SDavid du Colombier 	Mnt *m;
4993e12c5d1SDavid du Colombier 	Mntrpc *r;
5003e12c5d1SDavid du Colombier 
5013e12c5d1SDavid du Colombier 	m = mntchk(c);
5029a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
5033e12c5d1SDavid du Colombier 	if(waserror()) {
5043e12c5d1SDavid du Colombier 		mntfree(r);
5053e12c5d1SDavid du Colombier 		nexterror();
5063e12c5d1SDavid du Colombier 	}
5079a747e4fSDavid du Colombier 	r->request.type = type;
5083e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
5093e12c5d1SDavid du Colombier 	r->request.mode = omode;
5109a747e4fSDavid du Colombier 	if(type == Tcreate){
5119a747e4fSDavid du Colombier 		r->request.perm = perm;
5129a747e4fSDavid du Colombier 		r->request.name = name;
5139a747e4fSDavid du Colombier 	}
5143e12c5d1SDavid du Colombier 	mountrpc(m, r);
5153e12c5d1SDavid du Colombier 
5163e12c5d1SDavid du Colombier 	c->qid = r->reply.qid;
5173e12c5d1SDavid du Colombier 	c->offset = 0;
5183e12c5d1SDavid du Colombier 	c->mode = openmode(omode);
5199a747e4fSDavid du Colombier 	c->iounit = r->reply.iounit;
5209a747e4fSDavid du Colombier 	if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
5219a747e4fSDavid du Colombier 		c->iounit = m->msize-IOHDRSZ;
5223e12c5d1SDavid du Colombier 	c->flag |= COPEN;
5233e12c5d1SDavid du Colombier 	poperror();
5243e12c5d1SDavid du Colombier 	mntfree(r);
5257dd7cddfSDavid du Colombier 
5267dd7cddfSDavid du Colombier 	if(c->flag & CCACHE)
5277dd7cddfSDavid du Colombier 		copen(c);
5287dd7cddfSDavid du Colombier 
5293e12c5d1SDavid du Colombier 	return c;
5303e12c5d1SDavid du Colombier }
5313e12c5d1SDavid du Colombier 
5329a747e4fSDavid du Colombier static Chan*
mntopen(Chan * c,int omode)5339a747e4fSDavid du Colombier mntopen(Chan *c, int omode)
5349a747e4fSDavid du Colombier {
5359a747e4fSDavid du Colombier 	return mntopencreate(Topen, c, nil, omode, 0);
5369a747e4fSDavid du Colombier }
5379a747e4fSDavid du Colombier 
5387dd7cddfSDavid du Colombier static void
mntcreate(Chan * c,char * name,int omode,ulong perm)5393e12c5d1SDavid du Colombier mntcreate(Chan *c, char *name, int omode, ulong perm)
5403e12c5d1SDavid du Colombier {
5419a747e4fSDavid du Colombier 	mntopencreate(Tcreate, c, name, omode, perm);
5423e12c5d1SDavid du Colombier }
5433e12c5d1SDavid du Colombier 
5447dd7cddfSDavid du Colombier static void
mntclunk(Chan * c,int t)5453e12c5d1SDavid du Colombier mntclunk(Chan *c, int t)
5463e12c5d1SDavid du Colombier {
5473e12c5d1SDavid du Colombier 	Mnt *m;
5483e12c5d1SDavid du Colombier 	Mntrpc *r;
5493e12c5d1SDavid du Colombier 
5503e12c5d1SDavid du Colombier 	m = mntchk(c);
5519a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
5523e12c5d1SDavid du Colombier 	if(waserror()){
5537dd7cddfSDavid du Colombier 		mntfree(r);
5543e12c5d1SDavid du Colombier 		nexterror();
5553e12c5d1SDavid du Colombier 	}
5563e12c5d1SDavid du Colombier 
5573e12c5d1SDavid du Colombier 	r->request.type = t;
5583e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
5593e12c5d1SDavid du Colombier 	mountrpc(m, r);
5607dd7cddfSDavid du Colombier 	mntfree(r);
5613e12c5d1SDavid du Colombier 	poperror();
5623e12c5d1SDavid du Colombier }
5633e12c5d1SDavid du Colombier 
5643e12c5d1SDavid du Colombier void
muxclose(Mnt * m)5659a747e4fSDavid du Colombier muxclose(Mnt *m)
5663e12c5d1SDavid du Colombier {
567219b2ee8SDavid du Colombier 	Mntrpc *q, *r;
5683e12c5d1SDavid du Colombier 
5693e12c5d1SDavid du Colombier 	for(q = m->queue; q; q = r) {
5703e12c5d1SDavid du Colombier 		r = q->list;
5713e12c5d1SDavid du Colombier 		mntfree(q);
5723e12c5d1SDavid du Colombier 	}
5733e12c5d1SDavid du Colombier 	m->id = 0;
5749a747e4fSDavid du Colombier 	free(m->version);
5759a747e4fSDavid du Colombier 	m->version = nil;
5763e12c5d1SDavid du Colombier 	mntpntfree(m);
5773e12c5d1SDavid du Colombier }
578219b2ee8SDavid du Colombier 
579219b2ee8SDavid du Colombier void
mntpntfree(Mnt * m)5803e12c5d1SDavid du Colombier mntpntfree(Mnt *m)
5813e12c5d1SDavid du Colombier {
5823e12c5d1SDavid du Colombier 	Mnt *f, **l;
5839a747e4fSDavid du Colombier 	Queue *q;
5843e12c5d1SDavid du Colombier 
5853e12c5d1SDavid du Colombier 	lock(&mntalloc);
5863e12c5d1SDavid du Colombier 	l = &mntalloc.list;
5873e12c5d1SDavid du Colombier 	for(f = *l; f; f = f->list) {
5883e12c5d1SDavid du Colombier 		if(f == m) {
5893e12c5d1SDavid du Colombier 			*l = m->list;
5903e12c5d1SDavid du Colombier 			break;
5913e12c5d1SDavid du Colombier 		}
5923e12c5d1SDavid du Colombier 		l = &f->list;
5933e12c5d1SDavid du Colombier 	}
5943e12c5d1SDavid du Colombier 	m->list = mntalloc.mntfree;
5953e12c5d1SDavid du Colombier 	mntalloc.mntfree = m;
5969a747e4fSDavid du Colombier 	q = m->q;
5973e12c5d1SDavid du Colombier 	unlock(&mntalloc);
5989a747e4fSDavid du Colombier 
5999a747e4fSDavid du Colombier 	qfree(q);
6003e12c5d1SDavid du Colombier }
6013e12c5d1SDavid du Colombier 
6027dd7cddfSDavid du Colombier static void
mntclose(Chan * c)6033e12c5d1SDavid du Colombier mntclose(Chan *c)
6043e12c5d1SDavid du Colombier {
6053e12c5d1SDavid du Colombier 	mntclunk(c, Tclunk);
6063e12c5d1SDavid du Colombier }
6073e12c5d1SDavid du Colombier 
6087dd7cddfSDavid du Colombier static void
mntremove(Chan * c)6093e12c5d1SDavid du Colombier mntremove(Chan *c)
6103e12c5d1SDavid du Colombier {
6113e12c5d1SDavid du Colombier 	mntclunk(c, Tremove);
6123e12c5d1SDavid du Colombier }
6133e12c5d1SDavid du Colombier 
6149a747e4fSDavid du Colombier static int
mntwstat(Chan * c,uchar * dp,int n)6159a747e4fSDavid du Colombier mntwstat(Chan *c, uchar *dp, int n)
6163e12c5d1SDavid du Colombier {
6173e12c5d1SDavid du Colombier 	Mnt *m;
6183e12c5d1SDavid du Colombier 	Mntrpc *r;
6193e12c5d1SDavid du Colombier 
6203e12c5d1SDavid du Colombier 	m = mntchk(c);
6219a747e4fSDavid du Colombier 	r = mntralloc(c, m->msize);
6223e12c5d1SDavid du Colombier 	if(waserror()) {
6233e12c5d1SDavid du Colombier 		mntfree(r);
6243e12c5d1SDavid du Colombier 		nexterror();
6253e12c5d1SDavid du Colombier 	}
6263e12c5d1SDavid du Colombier 	r->request.type = Twstat;
6273e12c5d1SDavid du Colombier 	r->request.fid = c->fid;
6289a747e4fSDavid du Colombier 	r->request.nstat = n;
6299a747e4fSDavid du Colombier 	r->request.stat = dp;
6303e12c5d1SDavid du Colombier 	mountrpc(m, r);
6313e12c5d1SDavid du Colombier 	poperror();
6323e12c5d1SDavid du Colombier 	mntfree(r);
6339a747e4fSDavid du Colombier 	return n;
6347dd7cddfSDavid du Colombier }
6357dd7cddfSDavid du Colombier 
6367dd7cddfSDavid du Colombier static long
mntread(Chan * c,void * buf,long n,vlong off)6377dd7cddfSDavid du Colombier mntread(Chan *c, void *buf, long n, vlong off)
6383e12c5d1SDavid du Colombier {
6393e12c5d1SDavid du Colombier 	uchar *p, *e;
6409a747e4fSDavid du Colombier 	int nc, cache, isdir, dirlen;
6413e12c5d1SDavid du Colombier 
6427dd7cddfSDavid du Colombier 	isdir = 0;
6437dd7cddfSDavid du Colombier 	cache = c->flag & CCACHE;
6449a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR) {
6457dd7cddfSDavid du Colombier 		cache = 0;
6467dd7cddfSDavid du Colombier 		isdir = 1;
6477dd7cddfSDavid du Colombier 	}
6487dd7cddfSDavid du Colombier 
6497dd7cddfSDavid du Colombier 	p = buf;
6507dd7cddfSDavid du Colombier 	if(cache) {
6517dd7cddfSDavid du Colombier 		nc = cread(c, buf, n, off);
6527dd7cddfSDavid du Colombier 		if(nc > 0) {
6537dd7cddfSDavid du Colombier 			n -= nc;
6547dd7cddfSDavid du Colombier 			if(n == 0)
6557dd7cddfSDavid du Colombier 				return nc;
6567dd7cddfSDavid du Colombier 			p += nc;
6577dd7cddfSDavid du Colombier 			off += nc;
6587dd7cddfSDavid du Colombier 		}
6597dd7cddfSDavid du Colombier 		n = mntrdwr(Tread, c, p, n, off);
6607dd7cddfSDavid du Colombier 		cupdate(c, p, n, off);
6617dd7cddfSDavid du Colombier 		return n + nc;
6627dd7cddfSDavid du Colombier 	}
6637dd7cddfSDavid du Colombier 
6647dd7cddfSDavid du Colombier 	n = mntrdwr(Tread, c, buf, n, off);
6657dd7cddfSDavid du Colombier 	if(isdir) {
6669a747e4fSDavid du Colombier 		for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
6679a747e4fSDavid du Colombier 			dirlen = BIT16SZ+GBIT16(p);
6689a747e4fSDavid du Colombier 			if(p+dirlen > e)
6699a747e4fSDavid du Colombier 				break;
6709a747e4fSDavid du Colombier 			validstat(p, dirlen);
6713e12c5d1SDavid du Colombier 			mntdirfix(p, c);
6727dd7cddfSDavid du Colombier 		}
6739a747e4fSDavid du Colombier 		if(p != e)
6749a747e4fSDavid du Colombier 			error(Esbadstat);
6753e12c5d1SDavid du Colombier 	}
6769a747e4fSDavid du Colombier 	return n;
6777dd7cddfSDavid du Colombier }
6787dd7cddfSDavid du Colombier 
6797dd7cddfSDavid du Colombier static long
mntwrite(Chan * c,void * buf,long n,vlong off)6807dd7cddfSDavid du Colombier mntwrite(Chan *c, void *buf, long n, vlong off)
6817dd7cddfSDavid du Colombier {
6827dd7cddfSDavid du Colombier 	return mntrdwr(Twrite, c, buf, n, off);
6833e12c5d1SDavid du Colombier }
6843e12c5d1SDavid du Colombier 
6853e12c5d1SDavid du Colombier long
mntrdwr(int type,Chan * c,void * buf,long n,vlong off)6867dd7cddfSDavid du Colombier mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
6877dd7cddfSDavid du Colombier {
6887dd7cddfSDavid du Colombier 	Mnt *m;
6897dd7cddfSDavid du Colombier  	Mntrpc *r;
6907dd7cddfSDavid du Colombier 	char *uba;
6917dd7cddfSDavid du Colombier 	int cache;
6927dd7cddfSDavid du Colombier 	ulong cnt, nr, nreq;
6937dd7cddfSDavid du Colombier 
6947dd7cddfSDavid du Colombier 	m = mntchk(c);
6957dd7cddfSDavid du Colombier 	uba = buf;
6967dd7cddfSDavid du Colombier 	cnt = 0;
6977dd7cddfSDavid du Colombier 	cache = c->flag & CCACHE;
6989a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
6997dd7cddfSDavid du Colombier 		cache = 0;
7007dd7cddfSDavid du Colombier 	for(;;) {
7019a747e4fSDavid du Colombier 		r = mntralloc(c, m->msize);
7027dd7cddfSDavid du Colombier 		if(waserror()) {
7037dd7cddfSDavid du Colombier 			mntfree(r);
7047dd7cddfSDavid du Colombier 			nexterror();
7057dd7cddfSDavid du Colombier 		}
7067dd7cddfSDavid du Colombier 		r->request.type = type;
7077dd7cddfSDavid du Colombier 		r->request.fid = c->fid;
7087dd7cddfSDavid du Colombier 		r->request.offset = off;
7097dd7cddfSDavid du Colombier 		r->request.data = uba;
7109a747e4fSDavid du Colombier 		nr = n;
7119a747e4fSDavid du Colombier 		if(nr > m->msize-IOHDRSZ)
7129a747e4fSDavid du Colombier 			nr = m->msize-IOHDRSZ;
7139a747e4fSDavid du Colombier 		r->request.count = nr;
7147dd7cddfSDavid du Colombier 		mountrpc(m, r);
7157dd7cddfSDavid du Colombier 		nreq = r->request.count;
7167dd7cddfSDavid du Colombier 		nr = r->reply.count;
7177dd7cddfSDavid du Colombier 		if(nr > nreq)
7187dd7cddfSDavid du Colombier 			nr = nreq;
7197dd7cddfSDavid du Colombier 
7207dd7cddfSDavid du Colombier 		if(type == Tread)
7219a747e4fSDavid du Colombier 			r->b = bl2mem((uchar*)uba, r->b, nr);
7227dd7cddfSDavid du Colombier 		else if(cache)
7237dd7cddfSDavid du Colombier 			cwrite(c, (uchar*)uba, nr, off);
7247dd7cddfSDavid du Colombier 
7257dd7cddfSDavid du Colombier 		poperror();
7267dd7cddfSDavid du Colombier 		mntfree(r);
7277dd7cddfSDavid du Colombier 		off += nr;
7283e12c5d1SDavid du Colombier 		uba += nr;
7293e12c5d1SDavid du Colombier 		cnt += nr;
730219b2ee8SDavid du Colombier 		n -= nr;
7317dd7cddfSDavid du Colombier 		if(nr != nreq || n == 0 || up->nnote)
7323e12c5d1SDavid du Colombier 			break;
7333e12c5d1SDavid du Colombier 	}
7343e12c5d1SDavid du Colombier 	return cnt;
7353e12c5d1SDavid du Colombier }
7363e12c5d1SDavid du Colombier 
7373e12c5d1SDavid du Colombier void
mountrpc(Mnt * m,Mntrpc * r)7383e12c5d1SDavid du Colombier mountrpc(Mnt *m, Mntrpc *r)
7393e12c5d1SDavid du Colombier {
7409a747e4fSDavid du Colombier 	char *sn, *cn;
7417dd7cddfSDavid du Colombier 	int t;
7427dd7cddfSDavid du Colombier 
7437dd7cddfSDavid du Colombier 	r->reply.tag = 0;
7447dd7cddfSDavid du Colombier 	r->reply.type = Tmax;	/* can't ever be a valid message type */
7453e12c5d1SDavid du Colombier 
7463e12c5d1SDavid du Colombier 	mountio(m, r);
7477dd7cddfSDavid du Colombier 
7487dd7cddfSDavid du Colombier 	t = r->reply.type;
7497dd7cddfSDavid du Colombier 	switch(t) {
7507dd7cddfSDavid du Colombier 	case Rerror:
7513e12c5d1SDavid du Colombier 		error(r->reply.ename);
7527dd7cddfSDavid du Colombier 	case Rflush:
7533e12c5d1SDavid du Colombier 		error(Eintr);
7547dd7cddfSDavid du Colombier 	default:
7557dd7cddfSDavid du Colombier 		if(t == r->request.type+1)
7567dd7cddfSDavid du Colombier 			break;
7579a747e4fSDavid du Colombier 		sn = "?";
7584afe124fSDavid du Colombier 		if(m->c->path != nil)
7594afe124fSDavid du Colombier 			sn = m->c->path->s;
7609a747e4fSDavid du Colombier 		cn = "?";
7614afe124fSDavid du Colombier 		if(r->c != nil && r->c->path != nil)
7624afe124fSDavid du Colombier 			cn = r->c->path->s;
763567483c8SDavid du Colombier 		print("mnt: proc %s %lud: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
7649a747e4fSDavid du Colombier 			up->text, up->pid, sn, cn,
7659a747e4fSDavid du Colombier 			r, r->request.tag, r->request.fid, r->request.type,
7669a747e4fSDavid du Colombier 			r->reply.type, r->reply.tag);
7673e12c5d1SDavid du Colombier 		error(Emountrpc);
7683e12c5d1SDavid du Colombier 	}
7693e12c5d1SDavid du Colombier }
7703e12c5d1SDavid du Colombier 
7713e12c5d1SDavid du Colombier void
mountio(Mnt * m,Mntrpc * r)7723e12c5d1SDavid du Colombier mountio(Mnt *m, Mntrpc *r)
7733e12c5d1SDavid du Colombier {
7743e12c5d1SDavid du Colombier 	int n;
7753e12c5d1SDavid du Colombier 
7767dd7cddfSDavid du Colombier 	while(waserror()) {
7777dd7cddfSDavid du Colombier 		if(m->rip == up)
7787dd7cddfSDavid du Colombier 			mntgate(m);
7799a747e4fSDavid du Colombier 		if(strcmp(up->errstr, Eintr) != 0){
7807dd7cddfSDavid du Colombier 			mntflushfree(m, r);
7817dd7cddfSDavid du Colombier 			nexterror();
7827dd7cddfSDavid du Colombier 		}
7839a747e4fSDavid du Colombier 		r = mntflushalloc(r, m->msize);
7847dd7cddfSDavid du Colombier 	}
7857dd7cddfSDavid du Colombier 
7863e12c5d1SDavid du Colombier 	lock(m);
7873e12c5d1SDavid du Colombier 	r->m = m;
7883e12c5d1SDavid du Colombier 	r->list = m->queue;
7893e12c5d1SDavid du Colombier 	m->queue = r;
7903e12c5d1SDavid du Colombier 	unlock(m);
7913e12c5d1SDavid du Colombier 
7923e12c5d1SDavid du Colombier 	/* Transmit a file system rpc */
7939a747e4fSDavid du Colombier 	if(m->msize == 0)
7949a747e4fSDavid du Colombier 		panic("msize");
7959a747e4fSDavid du Colombier 	n = convS2M(&r->request, r->rpc, m->msize);
7967dd7cddfSDavid du Colombier 	if(n < 0)
7977dd7cddfSDavid du Colombier 		panic("bad message type in mountio");
7987dd7cddfSDavid du Colombier 	if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
7997dd7cddfSDavid du Colombier 		error(Emountrpc);
8007dd7cddfSDavid du Colombier 	r->stime = fastticks(nil);
8017dd7cddfSDavid du Colombier 	r->reqlen = n;
8023e12c5d1SDavid du Colombier 
8033e12c5d1SDavid du Colombier 	/* Gate readers onto the mount point one at a time */
8043e12c5d1SDavid du Colombier 	for(;;) {
8053e12c5d1SDavid du Colombier 		lock(m);
8063e12c5d1SDavid du Colombier 		if(m->rip == 0)
8073e12c5d1SDavid du Colombier 			break;
8083e12c5d1SDavid du Colombier 		unlock(m);
8093e12c5d1SDavid du Colombier 		sleep(&r->r, rpcattn, r);
8107dd7cddfSDavid du Colombier 		if(r->done){
8113e12c5d1SDavid du Colombier 			poperror();
8127dd7cddfSDavid du Colombier 			mntflushfree(m, r);
8133e12c5d1SDavid du Colombier 			return;
8143e12c5d1SDavid du Colombier 		}
8157dd7cddfSDavid du Colombier 	}
8167dd7cddfSDavid du Colombier 	m->rip = up;
8173e12c5d1SDavid du Colombier 	unlock(m);
8183e12c5d1SDavid du Colombier 	while(r->done == 0) {
8199a747e4fSDavid du Colombier 		if(mntrpcread(m, r) < 0)
8209a747e4fSDavid du Colombier 			error(Emountrpc);
8213e12c5d1SDavid du Colombier 		mountmux(m, r);
8223e12c5d1SDavid du Colombier 	}
8233e12c5d1SDavid du Colombier 	mntgate(m);
8247dd7cddfSDavid du Colombier 	poperror();
8257dd7cddfSDavid du Colombier 	mntflushfree(m, r);
8263e12c5d1SDavid du Colombier }
8273e12c5d1SDavid du Colombier 
8286a9fc400SDavid du Colombier static int
doread(Mnt * m,int len)8296a9fc400SDavid du Colombier doread(Mnt *m, int len)
8306a9fc400SDavid du Colombier {
8316a9fc400SDavid du Colombier 	Block *b;
8326a9fc400SDavid du Colombier 
8336a9fc400SDavid du Colombier 	while(qlen(m->q) < len){
8346a9fc400SDavid du Colombier 		b = devtab[m->c->type]->bread(m->c, m->msize, 0);
8356a9fc400SDavid du Colombier 		if(b == nil)
8366a9fc400SDavid du Colombier 			return -1;
83718027f8cSDavid du Colombier 		if(blocklen(b) == 0){
8386a9fc400SDavid du Colombier 			freeblist(b);
8396a9fc400SDavid du Colombier 			return -1;
8406a9fc400SDavid du Colombier 		}
8416a9fc400SDavid du Colombier 		qaddlist(m->q, b);
8426a9fc400SDavid du Colombier 	}
8436a9fc400SDavid du Colombier 	return 0;
8446a9fc400SDavid du Colombier }
8456a9fc400SDavid du Colombier 
8469a747e4fSDavid du Colombier int
mntrpcread(Mnt * m,Mntrpc * r)8473e12c5d1SDavid du Colombier mntrpcread(Mnt *m, Mntrpc *r)
8483e12c5d1SDavid du Colombier {
8499a747e4fSDavid du Colombier 	int i, t, len, hlen;
8509a747e4fSDavid du Colombier 	Block *b, **l, *nb;
8513e12c5d1SDavid du Colombier 
8523e12c5d1SDavid du Colombier 	r->reply.type = 0;
8533e12c5d1SDavid du Colombier 	r->reply.tag = 0;
8543e12c5d1SDavid du Colombier 
8559a747e4fSDavid du Colombier 	/* read at least length, type, and tag and pullup to a single block */
8566a9fc400SDavid du Colombier 	if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
8579a747e4fSDavid du Colombier 		return -1;
8589a747e4fSDavid du Colombier 	nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
8599a747e4fSDavid du Colombier 
860ed8191acSDavid du Colombier 	/* read in the rest of the message, avoid ridiculous (for now) message sizes */
8616a9fc400SDavid du Colombier 	len = GBIT32(nb->rp);
8626a9fc400SDavid du Colombier 	if(len > m->msize){
8636a9fc400SDavid du Colombier 		qdiscard(m->q, qlen(m->q));
8649a747e4fSDavid du Colombier 		return -1;
8659a747e4fSDavid du Colombier 	}
8666a9fc400SDavid du Colombier 	if(doread(m, len) < 0)
8676a9fc400SDavid du Colombier 		return -1;
8689a747e4fSDavid du Colombier 
8699a747e4fSDavid du Colombier 	/* pullup the header (i.e. everything except data) */
8709a747e4fSDavid du Colombier 	t = nb->rp[BIT32SZ];
8719a747e4fSDavid du Colombier 	switch(t){
8729a747e4fSDavid du Colombier 	case Rread:
8739a747e4fSDavid du Colombier 		hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
8749a747e4fSDavid du Colombier 		break;
8759a747e4fSDavid du Colombier 	default:
8769a747e4fSDavid du Colombier 		hlen = len;
8779a747e4fSDavid du Colombier 		break;
8789a747e4fSDavid du Colombier 	}
8799a747e4fSDavid du Colombier 	nb = pullupqueue(m->q, hlen);
8809a747e4fSDavid du Colombier 
8819a747e4fSDavid du Colombier 	if(convM2S(nb->rp, len, &r->reply) <= 0){
8829a747e4fSDavid du Colombier 		/* bad message, dump it */
8839a747e4fSDavid du Colombier 		print("mntrpcread: convM2S failed\n");
8849a747e4fSDavid du Colombier 		qdiscard(m->q, len);
8859a747e4fSDavid du Colombier 		return -1;
8869a747e4fSDavid du Colombier 	}
8879a747e4fSDavid du Colombier 
8889a747e4fSDavid du Colombier 	/* hang the data off of the fcall struct */
8899a747e4fSDavid du Colombier 	l = &r->b;
8909a747e4fSDavid du Colombier 	*l = nil;
8919a747e4fSDavid du Colombier 	do {
8929a747e4fSDavid du Colombier 		b = qremove(m->q);
8939a747e4fSDavid du Colombier 		if(hlen > 0){
8949a747e4fSDavid du Colombier 			b->rp += hlen;
8959a747e4fSDavid du Colombier 			len -= hlen;
8969a747e4fSDavid du Colombier 			hlen = 0;
8979a747e4fSDavid du Colombier 		}
8989a747e4fSDavid du Colombier 		i = BLEN(b);
8999a747e4fSDavid du Colombier 		if(i <= len){
9009a747e4fSDavid du Colombier 			len -= i;
9019a747e4fSDavid du Colombier 			*l = b;
9029a747e4fSDavid du Colombier 			l = &(b->next);
9039a747e4fSDavid du Colombier 		} else {
9049a747e4fSDavid du Colombier 			/* split block and put unused bit back */
9059a747e4fSDavid du Colombier 			nb = allocb(i-len);
9069a747e4fSDavid du Colombier 			memmove(nb->wp, b->rp+len, i-len);
9079a747e4fSDavid du Colombier 			b->wp = b->rp+len;
9089a747e4fSDavid du Colombier 			nb->wp += i-len;
9099a747e4fSDavid du Colombier 			qputback(m->q, nb);
9109a747e4fSDavid du Colombier 			*l = b;
9119a747e4fSDavid du Colombier 			return 0;
9129a747e4fSDavid du Colombier 		}
9139a747e4fSDavid du Colombier 	}while(len > 0);
9149a747e4fSDavid du Colombier 
9159a747e4fSDavid du Colombier 	return 0;
9163e12c5d1SDavid du Colombier }
9173e12c5d1SDavid du Colombier 
9183e12c5d1SDavid du Colombier void
mntgate(Mnt * m)9193e12c5d1SDavid du Colombier mntgate(Mnt *m)
9203e12c5d1SDavid du Colombier {
9213e12c5d1SDavid du Colombier 	Mntrpc *q;
9223e12c5d1SDavid du Colombier 
9233e12c5d1SDavid du Colombier 	lock(m);
9243e12c5d1SDavid du Colombier 	m->rip = 0;
9257dd7cddfSDavid du Colombier 	for(q = m->queue; q; q = q->list) {
9267dd7cddfSDavid du Colombier 		if(q->done == 0)
9277dd7cddfSDavid du Colombier 		if(wakeup(&q->r))
9287dd7cddfSDavid du Colombier 			break;
9293e12c5d1SDavid du Colombier 	}
9303e12c5d1SDavid du Colombier 	unlock(m);
9313e12c5d1SDavid du Colombier }
9323e12c5d1SDavid du Colombier 
9333e12c5d1SDavid du Colombier void
mountmux(Mnt * m,Mntrpc * r)9343e12c5d1SDavid du Colombier mountmux(Mnt *m, Mntrpc *r)
9353e12c5d1SDavid du Colombier {
9363e12c5d1SDavid du Colombier 	Mntrpc **l, *q;
9373e12c5d1SDavid du Colombier 
9383e12c5d1SDavid du Colombier 	lock(m);
9393e12c5d1SDavid du Colombier 	l = &m->queue;
9403e12c5d1SDavid du Colombier 	for(q = *l; q; q = q->list) {
9417dd7cddfSDavid du Colombier 		/* look for a reply to a message */
9427dd7cddfSDavid du Colombier 		if(q->request.tag == r->reply.tag) {
9433e12c5d1SDavid du Colombier 			*l = q->list;
9447dd7cddfSDavid du Colombier 			if(q != r) {
9457dd7cddfSDavid du Colombier 				/*
9467dd7cddfSDavid du Colombier 				 * Completed someone else.
9477dd7cddfSDavid du Colombier 				 * Trade pointers to receive buffer.
9487dd7cddfSDavid du Colombier 				 */
9497dd7cddfSDavid du Colombier 				q->reply = r->reply;
9509a747e4fSDavid du Colombier 				q->b = r->b;
9519a747e4fSDavid du Colombier 				r->b = nil;
9527dd7cddfSDavid du Colombier 			}
9533e12c5d1SDavid du Colombier 			q->done = 1;
9547dd7cddfSDavid du Colombier 			unlock(m);
9557dd7cddfSDavid du Colombier 			if(mntstats != nil)
9567dd7cddfSDavid du Colombier 				(*mntstats)(q->request.type,
9577dd7cddfSDavid du Colombier 					m->c, q->stime,
9587dd7cddfSDavid du Colombier 					q->reqlen + r->replen);
9597dd7cddfSDavid du Colombier 			if(q != r)
9603e12c5d1SDavid du Colombier 				wakeup(&q->r);
9613e12c5d1SDavid du Colombier 			return;
9623e12c5d1SDavid du Colombier 		}
9633e12c5d1SDavid du Colombier 		l = &q->list;
9643e12c5d1SDavid du Colombier 	}
9653e12c5d1SDavid du Colombier 	unlock(m);
9669a747e4fSDavid du Colombier 	print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
9673e12c5d1SDavid du Colombier }
9683e12c5d1SDavid du Colombier 
9697dd7cddfSDavid du Colombier /*
9707dd7cddfSDavid du Colombier  * Create a new flush request and chain the previous
9717dd7cddfSDavid du Colombier  * requests from it
9727dd7cddfSDavid du Colombier  */
9737dd7cddfSDavid du Colombier Mntrpc*
mntflushalloc(Mntrpc * r,ulong iounit)9749a747e4fSDavid du Colombier mntflushalloc(Mntrpc *r, ulong iounit)
9753e12c5d1SDavid du Colombier {
9767dd7cddfSDavid du Colombier 	Mntrpc *fr;
9773e12c5d1SDavid du Colombier 
9789a747e4fSDavid du Colombier 	fr = mntralloc(0, iounit);
9793e12c5d1SDavid du Colombier 
9807dd7cddfSDavid du Colombier 	fr->request.type = Tflush;
9817dd7cddfSDavid du Colombier 	if(r->request.type == Tflush)
9827dd7cddfSDavid du Colombier 		fr->request.oldtag = r->request.oldtag;
9837dd7cddfSDavid du Colombier 	else
9847dd7cddfSDavid du Colombier 		fr->request.oldtag = r->request.tag;
9857dd7cddfSDavid du Colombier 	fr->flushed = r;
9863e12c5d1SDavid du Colombier 
9877dd7cddfSDavid du Colombier 	return fr;
9883e12c5d1SDavid du Colombier }
9897dd7cddfSDavid du Colombier 
9907dd7cddfSDavid du Colombier /*
9917dd7cddfSDavid du Colombier  *  Free a chain of flushes.  Remove each unanswered
9927dd7cddfSDavid du Colombier  *  flush and the original message from the unanswered
9937dd7cddfSDavid du Colombier  *  request queue.  Mark the original message as done
9947dd7cddfSDavid du Colombier  *  and if it hasn't been answered set the reply to to
9957dd7cddfSDavid du Colombier  *  Rflush.
9967dd7cddfSDavid du Colombier  */
9977dd7cddfSDavid du Colombier void
mntflushfree(Mnt * m,Mntrpc * r)9987dd7cddfSDavid du Colombier mntflushfree(Mnt *m, Mntrpc *r)
9997dd7cddfSDavid du Colombier {
10007dd7cddfSDavid du Colombier 	Mntrpc *fr;
10017dd7cddfSDavid du Colombier 
10027dd7cddfSDavid du Colombier 	while(r){
10037dd7cddfSDavid du Colombier 		fr = r->flushed;
10047dd7cddfSDavid du Colombier 		if(!r->done){
10057dd7cddfSDavid du Colombier 			r->reply.type = Rflush;
10067dd7cddfSDavid du Colombier 			mntqrm(m, r);
10077dd7cddfSDavid du Colombier 		}
10087dd7cddfSDavid du Colombier 		if(fr)
10097dd7cddfSDavid du Colombier 			mntfree(r);
10107dd7cddfSDavid du Colombier 		r = fr;
10117dd7cddfSDavid du Colombier 	}
10123e12c5d1SDavid du Colombier }
10133e12c5d1SDavid du Colombier 
1014d9306527SDavid du Colombier int
alloctag(void)1015d9306527SDavid du Colombier alloctag(void)
1016d9306527SDavid du Colombier {
1017d9306527SDavid du Colombier 	int i, j;
1018d9306527SDavid du Colombier 	ulong v;
1019d9306527SDavid du Colombier 
1020d9306527SDavid du Colombier 	for(i = 0; i < NMASK; i++){
1021d9306527SDavid du Colombier 		v = mntalloc.tagmask[i];
1022d9306527SDavid du Colombier 		if(v == ~0UL)
1023d9306527SDavid du Colombier 			continue;
1024d9306527SDavid du Colombier 		for(j = 0; j < 1<<TAGSHIFT; j++)
1025d9306527SDavid du Colombier 			if((v & (1<<j)) == 0){
1026d9306527SDavid du Colombier 				mntalloc.tagmask[i] |= 1<<j;
1027d9306527SDavid du Colombier 				return (i<<TAGSHIFT) + j;
1028d9306527SDavid du Colombier 			}
1029d9306527SDavid du Colombier 	}
1030d9306527SDavid du Colombier 	panic("no friggin tags left");
1031d9306527SDavid du Colombier 	return NOTAG;
1032d9306527SDavid du Colombier }
1033d9306527SDavid du Colombier 
1034d9306527SDavid du Colombier void
freetag(int t)1035d9306527SDavid du Colombier freetag(int t)
1036d9306527SDavid du Colombier {
1037d9306527SDavid du Colombier 	mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1038d9306527SDavid du Colombier }
1039d9306527SDavid du Colombier 
10403e12c5d1SDavid du Colombier Mntrpc*
mntralloc(Chan * c,ulong msize)10419a747e4fSDavid du Colombier mntralloc(Chan *c, ulong msize)
10423e12c5d1SDavid du Colombier {
10433e12c5d1SDavid du Colombier 	Mntrpc *new;
10443e12c5d1SDavid du Colombier 
10453e12c5d1SDavid du Colombier 	lock(&mntalloc);
10463e12c5d1SDavid du Colombier 	new = mntalloc.rpcfree;
10477dd7cddfSDavid du Colombier 	if(new == nil){
10487dd7cddfSDavid du Colombier 		new = malloc(sizeof(Mntrpc));
10497dd7cddfSDavid du Colombier 		if(new == nil) {
10507dd7cddfSDavid du Colombier 			unlock(&mntalloc);
10517dd7cddfSDavid du Colombier 			exhausted("mount rpc header");
10527dd7cddfSDavid du Colombier 		}
10537dd7cddfSDavid du Colombier 		/*
10547dd7cddfSDavid du Colombier 		 * The header is split from the data buffer as
10557dd7cddfSDavid du Colombier 		 * mountmux may swap the buffer with another header.
10567dd7cddfSDavid du Colombier 		 */
10579a747e4fSDavid du Colombier 		new->rpc = mallocz(msize, 0);
10587dd7cddfSDavid du Colombier 		if(new->rpc == nil){
10597dd7cddfSDavid du Colombier 			free(new);
10603e12c5d1SDavid du Colombier 			unlock(&mntalloc);
10613e12c5d1SDavid du Colombier 			exhausted("mount rpc buffer");
10623e12c5d1SDavid du Colombier 		}
10639a747e4fSDavid du Colombier 		new->rpclen = msize;
1064d9306527SDavid du Colombier 		new->request.tag = alloctag();
10653e12c5d1SDavid du Colombier 	}
10667dd7cddfSDavid du Colombier 	else {
10677dd7cddfSDavid du Colombier 		mntalloc.rpcfree = new->list;
10687dd7cddfSDavid du Colombier 		mntalloc.nrpcfree--;
10699a747e4fSDavid du Colombier 		if(new->rpclen < msize){
10709a747e4fSDavid du Colombier 			free(new->rpc);
10719a747e4fSDavid du Colombier 			new->rpc = mallocz(msize, 0);
10729a747e4fSDavid du Colombier 			if(new->rpc == nil){
10739a747e4fSDavid du Colombier 				free(new);
10749a747e4fSDavid du Colombier 				mntalloc.nrpcused--;
10759a747e4fSDavid du Colombier 				unlock(&mntalloc);
10769a747e4fSDavid du Colombier 				exhausted("mount rpc buffer");
10779a747e4fSDavid du Colombier 			}
10789a747e4fSDavid du Colombier 			new->rpclen = msize;
10799a747e4fSDavid du Colombier 		}
10807dd7cddfSDavid du Colombier 	}
10817dd7cddfSDavid du Colombier 	mntalloc.nrpcused++;
10823e12c5d1SDavid du Colombier 	unlock(&mntalloc);
10837dd7cddfSDavid du Colombier 	new->c = c;
10843e12c5d1SDavid du Colombier 	new->done = 0;
10857dd7cddfSDavid du Colombier 	new->flushed = nil;
10869a747e4fSDavid du Colombier 	new->b = nil;
10873e12c5d1SDavid du Colombier 	return new;
10883e12c5d1SDavid du Colombier }
10893e12c5d1SDavid du Colombier 
10903e12c5d1SDavid du Colombier void
mntfree(Mntrpc * r)10913e12c5d1SDavid du Colombier mntfree(Mntrpc *r)
10923e12c5d1SDavid du Colombier {
10939a747e4fSDavid du Colombier 	if(r->b != nil)
10949a747e4fSDavid du Colombier 		freeblist(r->b);
10953e12c5d1SDavid du Colombier 	lock(&mntalloc);
10967dd7cddfSDavid du Colombier 	if(mntalloc.nrpcfree >= 10){
10977dd7cddfSDavid du Colombier 		free(r->rpc);
1098d9306527SDavid du Colombier 		freetag(r->request.tag);
1099a23bc242SDavid du Colombier 		free(r);
11007dd7cddfSDavid du Colombier 	}
11017dd7cddfSDavid du Colombier 	else{
11023e12c5d1SDavid du Colombier 		r->list = mntalloc.rpcfree;
11033e12c5d1SDavid du Colombier 		mntalloc.rpcfree = r;
11047dd7cddfSDavid du Colombier 		mntalloc.nrpcfree++;
11057dd7cddfSDavid du Colombier 	}
11067dd7cddfSDavid du Colombier 	mntalloc.nrpcused--;
11073e12c5d1SDavid du Colombier 	unlock(&mntalloc);
11083e12c5d1SDavid du Colombier }
11093e12c5d1SDavid du Colombier 
11103e12c5d1SDavid du Colombier void
mntqrm(Mnt * m,Mntrpc * r)11113e12c5d1SDavid du Colombier mntqrm(Mnt *m, Mntrpc *r)
11123e12c5d1SDavid du Colombier {
11133e12c5d1SDavid du Colombier 	Mntrpc **l, *f;
11143e12c5d1SDavid du Colombier 
11153e12c5d1SDavid du Colombier 	lock(m);
11163e12c5d1SDavid du Colombier 	r->done = 1;
11173e12c5d1SDavid du Colombier 
11183e12c5d1SDavid du Colombier 	l = &m->queue;
11193e12c5d1SDavid du Colombier 	for(f = *l; f; f = f->list) {
11203e12c5d1SDavid du Colombier 		if(f == r) {
11213e12c5d1SDavid du Colombier 			*l = r->list;
11223e12c5d1SDavid du Colombier 			break;
11233e12c5d1SDavid du Colombier 		}
11243e12c5d1SDavid du Colombier 		l = &f->list;
11253e12c5d1SDavid du Colombier 	}
11263e12c5d1SDavid du Colombier 	unlock(m);
11273e12c5d1SDavid du Colombier }
11283e12c5d1SDavid du Colombier 
11293e12c5d1SDavid du Colombier Mnt*
mntchk(Chan * c)11303e12c5d1SDavid du Colombier mntchk(Chan *c)
11313e12c5d1SDavid du Colombier {
11323e12c5d1SDavid du Colombier 	Mnt *m;
11333e12c5d1SDavid du Colombier 
11349a747e4fSDavid du Colombier 	/* This routine is mostly vestiges of prior lives; now it's just sanity checking */
11359a747e4fSDavid du Colombier 
11369a747e4fSDavid du Colombier 	if(c->mchan == nil)
11374afe124fSDavid du Colombier 		panic("mntchk 1: nil mchan c %s\n", chanpath(c));
11389a747e4fSDavid du Colombier 
11399a747e4fSDavid du Colombier 	m = c->mchan->mux;
11409a747e4fSDavid du Colombier 
11419a747e4fSDavid du Colombier 	if(m == nil)
11424afe124fSDavid du Colombier 		print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
11437dd7cddfSDavid du Colombier 
11447dd7cddfSDavid du Colombier 	/*
11458cd4f5a6SDavid du Colombier 	 * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
11467dd7cddfSDavid du Colombier 	 */
11477dd7cddfSDavid du Colombier 	if(m->id == 0 || m->id >= c->dev)
11489a747e4fSDavid du Colombier 		panic("mntchk 3: can't happen");
11497dd7cddfSDavid du Colombier 
11503e12c5d1SDavid du Colombier 	return m;
11513e12c5d1SDavid du Colombier }
11523e12c5d1SDavid du Colombier 
11539a747e4fSDavid du Colombier /*
11549a747e4fSDavid du Colombier  * Rewrite channel type and dev for in-flight data to
11559a747e4fSDavid du Colombier  * reflect local values.  These entries are known to be
11569a747e4fSDavid du Colombier  * the first two in the Dir encoding after the count.
11579a747e4fSDavid du Colombier  */
11583e12c5d1SDavid du Colombier void
mntdirfix(uchar * dirbuf,Chan * c)11593e12c5d1SDavid du Colombier mntdirfix(uchar *dirbuf, Chan *c)
11603e12c5d1SDavid du Colombier {
11619a747e4fSDavid du Colombier 	uint r;
11627dd7cddfSDavid du Colombier 
11637dd7cddfSDavid du Colombier 	r = devtab[c->type]->dc;
11649a747e4fSDavid du Colombier 	dirbuf += BIT16SZ;	/* skip count */
11659a747e4fSDavid du Colombier 	PBIT16(dirbuf, r);
11669a747e4fSDavid du Colombier 	dirbuf += BIT16SZ;
11679a747e4fSDavid du Colombier 	PBIT32(dirbuf, c->dev);
11683e12c5d1SDavid du Colombier }
11693e12c5d1SDavid du Colombier 
11703e12c5d1SDavid du Colombier int
rpcattn(void * v)11717dd7cddfSDavid du Colombier rpcattn(void *v)
11723e12c5d1SDavid du Colombier {
11737dd7cddfSDavid du Colombier 	Mntrpc *r;
11747dd7cddfSDavid du Colombier 
11757dd7cddfSDavid du Colombier 	r = v;
11763e12c5d1SDavid du Colombier 	return r->done || r->m->rip == 0;
11773e12c5d1SDavid du Colombier }
11787dd7cddfSDavid du Colombier 
11797dd7cddfSDavid du Colombier Dev mntdevtab = {
11807dd7cddfSDavid du Colombier 	'M',
11817dd7cddfSDavid du Colombier 	"mnt",
11827dd7cddfSDavid du Colombier 
11837dd7cddfSDavid du Colombier 	mntreset,
11847dd7cddfSDavid du Colombier 	devinit,
11859a747e4fSDavid du Colombier 	devshutdown,
11867dd7cddfSDavid du Colombier 	mntattach,
11877dd7cddfSDavid du Colombier 	mntwalk,
11887dd7cddfSDavid du Colombier 	mntstat,
11897dd7cddfSDavid du Colombier 	mntopen,
11907dd7cddfSDavid du Colombier 	mntcreate,
11917dd7cddfSDavid du Colombier 	mntclose,
11927dd7cddfSDavid du Colombier 	mntread,
11937dd7cddfSDavid du Colombier 	devbread,
11947dd7cddfSDavid du Colombier 	mntwrite,
11957dd7cddfSDavid du Colombier 	devbwrite,
11967dd7cddfSDavid du Colombier 	mntremove,
11977dd7cddfSDavid du Colombier 	mntwstat,
11987dd7cddfSDavid du Colombier };
1199