xref: /plan9/sys/src/cmd/unix/drawterm/kern/devmnt.c (revision 96cbc34f1b36a29efdcfd47b10e70703a690febc)
18ccd4a63SDavid du Colombier #include	"u.h"
28ccd4a63SDavid du Colombier #include	"lib.h"
38ccd4a63SDavid du Colombier #include	"dat.h"
48ccd4a63SDavid du Colombier #include	"fns.h"
58ccd4a63SDavid du Colombier #include	"error.h"
68ccd4a63SDavid du Colombier 
78ccd4a63SDavid du Colombier /*
88ccd4a63SDavid du Colombier  * References are managed as follows:
98ccd4a63SDavid du Colombier  * The channel to the server - a network connection or pipe - has one
108ccd4a63SDavid du Colombier  * reference for every Chan open on the server.  The server channel has
118ccd4a63SDavid du Colombier  * c->mux set to the Mnt used for muxing control to that server.  Mnts
128ccd4a63SDavid du Colombier  * have no reference count; they go away when c goes away.
138ccd4a63SDavid du Colombier  * Each channel derived from the mount point has mchan set to c,
148ccd4a63SDavid du Colombier  * and increfs/decrefs mchan to manage references on the server
158ccd4a63SDavid du Colombier  * connection.
168ccd4a63SDavid du Colombier  */
178ccd4a63SDavid du Colombier 
188ccd4a63SDavid du Colombier #define MAXRPC (IOHDRSZ+8192)
198ccd4a63SDavid du Colombier 
208ccd4a63SDavid du Colombier struct Mntrpc
218ccd4a63SDavid du Colombier {
228ccd4a63SDavid du Colombier 	Chan*	c;		/* Channel for whom we are working */
238ccd4a63SDavid du Colombier 	Mntrpc*	list;		/* Free/pending list */
248ccd4a63SDavid du Colombier 	Fcall	request;	/* Outgoing file system protocol message */
258ccd4a63SDavid du Colombier 	Fcall 	reply;		/* Incoming reply */
268ccd4a63SDavid du Colombier 	Mnt*	m;		/* Mount device during rpc */
278ccd4a63SDavid du Colombier 	Rendez	r;		/* Place to hang out */
288ccd4a63SDavid du Colombier 	uchar*	rpc;		/* I/O Data buffer */
298ccd4a63SDavid du Colombier 	uint		rpclen;	/* len of buffer */
308ccd4a63SDavid du Colombier 	Block	*b;		/* reply blocks */
318ccd4a63SDavid du Colombier 	char	done;		/* Rpc completed */
328ccd4a63SDavid du Colombier 	uvlong	stime;		/* start time for mnt statistics */
338ccd4a63SDavid du Colombier 	ulong	reqlen;		/* request length for mnt statistics */
348ccd4a63SDavid du Colombier 	ulong	replen;		/* reply length for mnt statistics */
358ccd4a63SDavid du Colombier 	Mntrpc*	flushed;	/* message this one flushes */
368ccd4a63SDavid du Colombier };
378ccd4a63SDavid du Colombier 
388ccd4a63SDavid du Colombier enum
398ccd4a63SDavid du Colombier {
408ccd4a63SDavid du Colombier 	TAGSHIFT = 5,			/* ulong has to be 32 bits */
418ccd4a63SDavid du Colombier 	TAGMASK = (1<<TAGSHIFT)-1,
428ccd4a63SDavid du Colombier 	NMASK = (64*1024)>>TAGSHIFT,
438ccd4a63SDavid du Colombier };
448ccd4a63SDavid du Colombier 
458ccd4a63SDavid du Colombier struct Mntalloc
468ccd4a63SDavid du Colombier {
478ccd4a63SDavid du Colombier 	Lock lk;
488ccd4a63SDavid du Colombier 	Mnt*	list;		/* Mount devices in use */
498ccd4a63SDavid du Colombier 	Mnt*	mntfree;	/* Free list */
508ccd4a63SDavid du Colombier 	Mntrpc*	rpcfree;
518ccd4a63SDavid du Colombier 	int	nrpcfree;
528ccd4a63SDavid du Colombier 	int	nrpcused;
538ccd4a63SDavid du Colombier 	ulong	id;
548ccd4a63SDavid du Colombier 	ulong	tagmask[NMASK];
558ccd4a63SDavid du Colombier }mntalloc;
568ccd4a63SDavid du Colombier 
578ccd4a63SDavid du Colombier void	mattach(Mnt*, Chan*, char*);
588ccd4a63SDavid du Colombier Mnt*	mntchk(Chan*);
598ccd4a63SDavid du Colombier void	mntdirfix(uchar*, Chan*);
608ccd4a63SDavid du Colombier Mntrpc*	mntflushalloc(Mntrpc*, ulong);
618ccd4a63SDavid du Colombier void	mntflushfree(Mnt*, Mntrpc*);
628ccd4a63SDavid du Colombier void	mntfree(Mntrpc*);
638ccd4a63SDavid du Colombier void	mntgate(Mnt*);
648ccd4a63SDavid du Colombier void	mntpntfree(Mnt*);
658ccd4a63SDavid du Colombier void	mntqrm(Mnt*, Mntrpc*);
668ccd4a63SDavid du Colombier Mntrpc*	mntralloc(Chan*, ulong);
678ccd4a63SDavid du Colombier long	mntrdwr(int, Chan*, void*, long, vlong);
688ccd4a63SDavid du Colombier int	mntrpcread(Mnt*, Mntrpc*);
698ccd4a63SDavid du Colombier void	mountio(Mnt*, Mntrpc*);
708ccd4a63SDavid du Colombier void	mountmux(Mnt*, Mntrpc*);
718ccd4a63SDavid du Colombier void	mountrpc(Mnt*, Mntrpc*);
728ccd4a63SDavid du Colombier int	rpcattn(void*);
738ccd4a63SDavid du Colombier Chan*	mntchan(void);
748ccd4a63SDavid du Colombier 
758ccd4a63SDavid du Colombier char	Esbadstat[] = "invalid directory entry received from server";
768ccd4a63SDavid du Colombier char Enoversion[] = "version not established for mount channel";
778ccd4a63SDavid du Colombier 
788ccd4a63SDavid du Colombier 
798ccd4a63SDavid du Colombier void (*mntstats)(int, Chan*, uvlong, ulong);
808ccd4a63SDavid du Colombier 
818ccd4a63SDavid du Colombier static void
mntreset(void)828ccd4a63SDavid du Colombier mntreset(void)
838ccd4a63SDavid du Colombier {
848ccd4a63SDavid du Colombier 	mntalloc.id = 1;
858ccd4a63SDavid du Colombier 	mntalloc.tagmask[0] = 1;			/* don't allow 0 as a tag */
868ccd4a63SDavid du Colombier 	mntalloc.tagmask[NMASK-1] = 0x80000000UL;	/* don't allow NOTAG */
878ccd4a63SDavid du Colombier 	fmtinstall('F', fcallfmt);
888ccd4a63SDavid du Colombier 	fmtinstall('D', dirfmt);
898ccd4a63SDavid du Colombier /* We can't install %M since eipfmt does and is used in the kernel [sape] */
908ccd4a63SDavid du Colombier 
918ccd4a63SDavid du Colombier 	cinit();
928ccd4a63SDavid du Colombier }
938ccd4a63SDavid du Colombier 
948ccd4a63SDavid du Colombier /*
958ccd4a63SDavid du Colombier  * Version is not multiplexed: message sent only once per connection.
968ccd4a63SDavid du Colombier  */
978ccd4a63SDavid du Colombier long
mntversion(Chan * c,char * version,int msize,int returnlen)988ccd4a63SDavid du Colombier mntversion(Chan *c, char *version, int msize, int returnlen)
998ccd4a63SDavid du Colombier {
1008ccd4a63SDavid du Colombier 	Fcall f;
1018ccd4a63SDavid du Colombier 	uchar *msg;
1028ccd4a63SDavid du Colombier 	Mnt *m;
1038ccd4a63SDavid du Colombier 	char *v;
1048ccd4a63SDavid du Colombier 	long k, l;
1058ccd4a63SDavid du Colombier 	uvlong oo;
1068ccd4a63SDavid du Colombier 	char buf[128];
1078ccd4a63SDavid du Colombier 
1088ccd4a63SDavid du Colombier 	qlock(&c->umqlock);	/* make sure no one else does this until we've established ourselves */
1098ccd4a63SDavid du Colombier 	if(waserror()){
1108ccd4a63SDavid du Colombier 		qunlock(&c->umqlock);
1118ccd4a63SDavid du Colombier 		nexterror();
1128ccd4a63SDavid du Colombier 	}
1138ccd4a63SDavid du Colombier 
1148ccd4a63SDavid du Colombier 	/* defaults */
1158ccd4a63SDavid du Colombier 	if(msize == 0)
1168ccd4a63SDavid du Colombier 		msize = MAXRPC;
1178ccd4a63SDavid du Colombier 	if(msize > c->iounit && c->iounit != 0)
1188ccd4a63SDavid du Colombier 		msize = c->iounit;
1198ccd4a63SDavid du Colombier 	v = version;
1208ccd4a63SDavid du Colombier 	if(v == nil || v[0] == '\0')
1218ccd4a63SDavid du Colombier 		v = VERSION9P;
1228ccd4a63SDavid du Colombier 
1238ccd4a63SDavid du Colombier 	/* validity */
1248ccd4a63SDavid du Colombier 	if(msize < 0)
1258ccd4a63SDavid du Colombier 		error("bad iounit in version call");
1268ccd4a63SDavid du Colombier 	if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
1278ccd4a63SDavid du Colombier 		error("bad 9P version specification");
1288ccd4a63SDavid du Colombier 
1298ccd4a63SDavid du Colombier 	m = c->mux;
1308ccd4a63SDavid du Colombier 
1318ccd4a63SDavid du Colombier 	if(m != nil){
1328ccd4a63SDavid du Colombier 		qunlock(&c->umqlock);
1338ccd4a63SDavid du Colombier 		poperror();
1348ccd4a63SDavid du Colombier 
1358ccd4a63SDavid du Colombier 		strecpy(buf, buf+sizeof buf, m->version);
1368ccd4a63SDavid du Colombier 		k = strlen(buf);
1378ccd4a63SDavid du Colombier 		if(strncmp(buf, v, k) != 0){
1388ccd4a63SDavid du Colombier 			snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
1398ccd4a63SDavid du Colombier 			error(buf);
1408ccd4a63SDavid du Colombier 		}
1418ccd4a63SDavid du Colombier 		if(returnlen > 0){
1428ccd4a63SDavid du Colombier 			if(returnlen < k)
1438ccd4a63SDavid du Colombier 				error(Eshort);
1448ccd4a63SDavid du Colombier 			memmove(version, buf, k);
1458ccd4a63SDavid du Colombier 		}
1468ccd4a63SDavid du Colombier 		return k;
1478ccd4a63SDavid du Colombier 	}
1488ccd4a63SDavid du Colombier 
1498ccd4a63SDavid du Colombier 	f.type = Tversion;
1508ccd4a63SDavid du Colombier 	f.tag = NOTAG;
1518ccd4a63SDavid du Colombier 	f.msize = msize;
1528ccd4a63SDavid du Colombier 	f.version = v;
1538ccd4a63SDavid du Colombier 	msg = malloc(8192+IOHDRSZ);
1548ccd4a63SDavid du Colombier 	if(msg == nil)
1558ccd4a63SDavid du Colombier 		exhausted("version memory");
1568ccd4a63SDavid du Colombier 	if(waserror()){
1578ccd4a63SDavid du Colombier 		free(msg);
1588ccd4a63SDavid du Colombier 		nexterror();
1598ccd4a63SDavid du Colombier 	}
1608ccd4a63SDavid du Colombier 	k = convS2M(&f, msg, 8192+IOHDRSZ);
1618ccd4a63SDavid du Colombier 	if(k == 0)
1628ccd4a63SDavid du Colombier 		error("bad fversion conversion on send");
1638ccd4a63SDavid du Colombier 
1648ccd4a63SDavid du Colombier 	lock(&c->ref.lk);
1658ccd4a63SDavid du Colombier 	oo = c->offset;
1668ccd4a63SDavid du Colombier 	c->offset += k;
1678ccd4a63SDavid du Colombier 	unlock(&c->ref.lk);
1688ccd4a63SDavid du Colombier 
1698ccd4a63SDavid du Colombier 	l = devtab[c->type]->write(c, msg, k, oo);
1708ccd4a63SDavid du Colombier 
1718ccd4a63SDavid du Colombier 	if(l < k){
1728ccd4a63SDavid du Colombier 		lock(&c->ref.lk);
1738ccd4a63SDavid du Colombier 		c->offset -= k - l;
1748ccd4a63SDavid du Colombier 		unlock(&c->ref.lk);
1758ccd4a63SDavid du Colombier 		error("short write in fversion");
1768ccd4a63SDavid du Colombier 	}
1778ccd4a63SDavid du Colombier 
1788ccd4a63SDavid du Colombier 	/* message sent; receive and decode reply */
1798ccd4a63SDavid du Colombier 	k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
1808ccd4a63SDavid du Colombier 	if(k <= 0)
1818ccd4a63SDavid du Colombier 		error("EOF receiving fversion reply");
1828ccd4a63SDavid du Colombier 
1838ccd4a63SDavid du Colombier 	lock(&c->ref.lk);
1848ccd4a63SDavid du Colombier 	c->offset += k;
1858ccd4a63SDavid du Colombier 	unlock(&c->ref.lk);
1868ccd4a63SDavid du Colombier 
1878ccd4a63SDavid du Colombier 	l = convM2S(msg, k, &f);
1888ccd4a63SDavid du Colombier 	if(l != k)
1898ccd4a63SDavid du Colombier 		error("bad fversion conversion on reply");
1908ccd4a63SDavid du Colombier 	if(f.type != Rversion){
1918ccd4a63SDavid du Colombier 		if(f.type == Rerror)
1928ccd4a63SDavid du Colombier 			error(f.ename);
1938ccd4a63SDavid du Colombier 		error("unexpected reply type in fversion");
1948ccd4a63SDavid du Colombier 	}
1958ccd4a63SDavid du Colombier 	if(f.msize > msize)
1968ccd4a63SDavid du Colombier 		error("server tries to increase msize in fversion");
1978ccd4a63SDavid du Colombier 	if(f.msize<256 || f.msize>1024*1024)
1988ccd4a63SDavid du Colombier 		error("nonsense value of msize in fversion");
199*96cbc34fSDavid du Colombier 	k = strlen(f.version);
200*96cbc34fSDavid du Colombier 	if(strncmp(f.version, v, k) != 0)
2018ccd4a63SDavid du Colombier 		error("bad 9P version returned from server");
2028ccd4a63SDavid du Colombier 
2038ccd4a63SDavid du Colombier 	/* now build Mnt associated with this connection */
2048ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
2058ccd4a63SDavid du Colombier 	m = mntalloc.mntfree;
2068ccd4a63SDavid du Colombier 	if(m != 0)
2078ccd4a63SDavid du Colombier 		mntalloc.mntfree = m->list;
2088ccd4a63SDavid du Colombier 	else {
2098ccd4a63SDavid du Colombier 		m = malloc(sizeof(Mnt));
2108ccd4a63SDavid du Colombier 		if(m == 0) {
2118ccd4a63SDavid du Colombier 			unlock(&mntalloc.lk);
2128ccd4a63SDavid du Colombier 			exhausted("mount devices");
2138ccd4a63SDavid du Colombier 		}
2148ccd4a63SDavid du Colombier 	}
2158ccd4a63SDavid du Colombier 	m->list = mntalloc.list;
2168ccd4a63SDavid du Colombier 	mntalloc.list = m;
2178ccd4a63SDavid du Colombier 	m->version = nil;
2188ccd4a63SDavid du Colombier 	kstrdup(&m->version, f.version);
2198ccd4a63SDavid du Colombier 	m->id = mntalloc.id++;
220ec59a3ddSDavid du Colombier 	m->q = qopen(10*MAXRPC, 0, 0, nil);
2218ccd4a63SDavid du Colombier 	m->msize = f.msize;
2228ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
2238ccd4a63SDavid du Colombier 
224*96cbc34fSDavid du Colombier 	if(returnlen > 0){
225*96cbc34fSDavid du Colombier 		if(returnlen < k)
226*96cbc34fSDavid du Colombier 			error(Eshort);
227*96cbc34fSDavid du Colombier 		memmove(version, f.version, k);
228*96cbc34fSDavid du Colombier 	}
229*96cbc34fSDavid du Colombier 
2308ccd4a63SDavid du Colombier 	poperror();	/* msg */
2318ccd4a63SDavid du Colombier 	free(msg);
2328ccd4a63SDavid du Colombier 
2338ccd4a63SDavid du Colombier 	lock(&m->lk);
2348ccd4a63SDavid du Colombier 	m->queue = 0;
2358ccd4a63SDavid du Colombier 	m->rip = 0;
2368ccd4a63SDavid du Colombier 
2378ccd4a63SDavid du Colombier 	c->flag |= CMSG;
2388ccd4a63SDavid du Colombier 	c->mux = m;
2398ccd4a63SDavid du Colombier 	m->c = c;
2408ccd4a63SDavid du Colombier 	unlock(&m->lk);
2418ccd4a63SDavid du Colombier 
2428ccd4a63SDavid du Colombier 	poperror();	/* c */
2438ccd4a63SDavid du Colombier 	qunlock(&c->umqlock);
2448ccd4a63SDavid du Colombier 
2458ccd4a63SDavid du Colombier 	return k;
2468ccd4a63SDavid du Colombier }
2478ccd4a63SDavid du Colombier 
2488ccd4a63SDavid du Colombier Chan*
mntauth(Chan * c,char * spec)2498ccd4a63SDavid du Colombier mntauth(Chan *c, char *spec)
2508ccd4a63SDavid du Colombier {
2518ccd4a63SDavid du Colombier 	Mnt *m;
2528ccd4a63SDavid du Colombier 	Mntrpc *r;
2538ccd4a63SDavid du Colombier 
2548ccd4a63SDavid du Colombier 	m = c->mux;
2558ccd4a63SDavid du Colombier 
2568ccd4a63SDavid du Colombier 	if(m == nil){
2578ccd4a63SDavid du Colombier 		mntversion(c, VERSION9P, MAXRPC, 0);
2588ccd4a63SDavid du Colombier 		m = c->mux;
2598ccd4a63SDavid du Colombier 		if(m == nil)
2608ccd4a63SDavid du Colombier 			error(Enoversion);
2618ccd4a63SDavid du Colombier 	}
2628ccd4a63SDavid du Colombier 
2638ccd4a63SDavid du Colombier 	c = mntchan();
2648ccd4a63SDavid du Colombier 	if(waserror()) {
2658ccd4a63SDavid du Colombier 		/* Close must not be called since it will
2668ccd4a63SDavid du Colombier 		 * call mnt recursively
2678ccd4a63SDavid du Colombier 		 */
2688ccd4a63SDavid du Colombier 		chanfree(c);
2698ccd4a63SDavid du Colombier 		nexterror();
2708ccd4a63SDavid du Colombier 	}
2718ccd4a63SDavid du Colombier 
2728ccd4a63SDavid du Colombier 	r = mntralloc(0, m->msize);
2738ccd4a63SDavid du Colombier 
2748ccd4a63SDavid du Colombier 	if(waserror()) {
2758ccd4a63SDavid du Colombier 		mntfree(r);
2768ccd4a63SDavid du Colombier 		nexterror();
2778ccd4a63SDavid du Colombier 	}
2788ccd4a63SDavid du Colombier 
2798ccd4a63SDavid du Colombier 	r->request.type = Tauth;
2808ccd4a63SDavid du Colombier 	r->request.afid = c->fid;
2818ccd4a63SDavid du Colombier 	r->request.uname = up->user;
2828ccd4a63SDavid du Colombier 	r->request.aname = spec;
2838ccd4a63SDavid du Colombier 	mountrpc(m, r);
2848ccd4a63SDavid du Colombier 
2858ccd4a63SDavid du Colombier 	c->qid = r->reply.aqid;
2868ccd4a63SDavid du Colombier 	c->mchan = m->c;
2878ccd4a63SDavid du Colombier 	incref(&m->c->ref);
2888ccd4a63SDavid du Colombier 	c->mqid = c->qid;
2898ccd4a63SDavid du Colombier 	c->mode = ORDWR;
2908ccd4a63SDavid du Colombier 
2918ccd4a63SDavid du Colombier 	poperror();	/* r */
2928ccd4a63SDavid du Colombier 	mntfree(r);
2938ccd4a63SDavid du Colombier 
2948ccd4a63SDavid du Colombier 	poperror();	/* c */
2958ccd4a63SDavid du Colombier 
2968ccd4a63SDavid du Colombier 	return c;
2978ccd4a63SDavid du Colombier 
2988ccd4a63SDavid du Colombier }
2998ccd4a63SDavid du Colombier 
3008ccd4a63SDavid du Colombier static Chan*
mntattach(char * muxattach)3018ccd4a63SDavid du Colombier mntattach(char *muxattach)
3028ccd4a63SDavid du Colombier {
3038ccd4a63SDavid du Colombier 	Mnt *m;
3048ccd4a63SDavid du Colombier 	Chan *c;
3058ccd4a63SDavid du Colombier 	Mntrpc *r;
3068ccd4a63SDavid du Colombier 	struct bogus{
3078ccd4a63SDavid du Colombier 		Chan	*chan;
3088ccd4a63SDavid du Colombier 		Chan	*authchan;
3098ccd4a63SDavid du Colombier 		char	*spec;
3108ccd4a63SDavid du Colombier 		int	flags;
3118ccd4a63SDavid du Colombier 	}bogus;
3128ccd4a63SDavid du Colombier 
3138ccd4a63SDavid du Colombier 	bogus = *((struct bogus *)muxattach);
3148ccd4a63SDavid du Colombier 	c = bogus.chan;
3158ccd4a63SDavid du Colombier 
3168ccd4a63SDavid du Colombier 	m = c->mux;
3178ccd4a63SDavid du Colombier 
3188ccd4a63SDavid du Colombier 	if(m == nil){
3198ccd4a63SDavid du Colombier 		mntversion(c, nil, 0, 0);
3208ccd4a63SDavid du Colombier 		m = c->mux;
3218ccd4a63SDavid du Colombier 		if(m == nil)
3228ccd4a63SDavid du Colombier 			error(Enoversion);
3238ccd4a63SDavid du Colombier 	}
3248ccd4a63SDavid du Colombier 
3258ccd4a63SDavid du Colombier 	c = mntchan();
3268ccd4a63SDavid du Colombier 	if(waserror()) {
3278ccd4a63SDavid du Colombier 		/* Close must not be called since it will
3288ccd4a63SDavid du Colombier 		 * call mnt recursively
3298ccd4a63SDavid du Colombier 		 */
3308ccd4a63SDavid du Colombier 		chanfree(c);
3318ccd4a63SDavid du Colombier 		nexterror();
3328ccd4a63SDavid du Colombier 	}
3338ccd4a63SDavid du Colombier 
3348ccd4a63SDavid du Colombier 	r = mntralloc(0, m->msize);
3358ccd4a63SDavid du Colombier 
3368ccd4a63SDavid du Colombier 	if(waserror()) {
3378ccd4a63SDavid du Colombier 		mntfree(r);
3388ccd4a63SDavid du Colombier 		nexterror();
3398ccd4a63SDavid du Colombier 	}
3408ccd4a63SDavid du Colombier 
3418ccd4a63SDavid du Colombier 	r->request.type = Tattach;
3428ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
3438ccd4a63SDavid du Colombier 	if(bogus.authchan == nil)
3448ccd4a63SDavid du Colombier 		r->request.afid = NOFID;
3458ccd4a63SDavid du Colombier 	else
3468ccd4a63SDavid du Colombier 		r->request.afid = bogus.authchan->fid;
3478ccd4a63SDavid du Colombier 	r->request.uname = up->user;
3488ccd4a63SDavid du Colombier 	r->request.aname = bogus.spec;
3498ccd4a63SDavid du Colombier 	mountrpc(m, r);
3508ccd4a63SDavid du Colombier 
3518ccd4a63SDavid du Colombier 	c->qid = r->reply.qid;
3528ccd4a63SDavid du Colombier 	c->mchan = m->c;
3538ccd4a63SDavid du Colombier 	incref(&m->c->ref);
3548ccd4a63SDavid du Colombier 	c->mqid = c->qid;
3558ccd4a63SDavid du Colombier 
3568ccd4a63SDavid du Colombier 	poperror();	/* r */
3578ccd4a63SDavid du Colombier 	mntfree(r);
3588ccd4a63SDavid du Colombier 
3598ccd4a63SDavid du Colombier 	poperror();	/* c */
3608ccd4a63SDavid du Colombier 
3618ccd4a63SDavid du Colombier 	if(bogus.flags&MCACHE)
3628ccd4a63SDavid du Colombier 		c->flag |= CCACHE;
3638ccd4a63SDavid du Colombier 	return c;
3648ccd4a63SDavid du Colombier }
3658ccd4a63SDavid du Colombier 
3668ccd4a63SDavid du Colombier Chan*
mntchan(void)3678ccd4a63SDavid du Colombier mntchan(void)
3688ccd4a63SDavid du Colombier {
3698ccd4a63SDavid du Colombier 	Chan *c;
3708ccd4a63SDavid du Colombier 
3718ccd4a63SDavid du Colombier 	c = devattach('M', 0);
3728ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
3738ccd4a63SDavid du Colombier 	c->dev = mntalloc.id++;
3748ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
3758ccd4a63SDavid du Colombier 
3768ccd4a63SDavid du Colombier 	if(c->mchan)
3778ccd4a63SDavid du Colombier 		panic("mntchan non-zero %p", c->mchan);
3788ccd4a63SDavid du Colombier 	return c;
3798ccd4a63SDavid du Colombier }
3808ccd4a63SDavid du Colombier 
3818ccd4a63SDavid du Colombier static Walkqid*
mntwalk(Chan * c,Chan * nc,char ** name,int nname)3828ccd4a63SDavid du Colombier mntwalk(Chan *c, Chan *nc, char **name, int nname)
3838ccd4a63SDavid du Colombier {
3848ccd4a63SDavid du Colombier 	int i, alloc;
3858ccd4a63SDavid du Colombier 	Mnt *m;
3868ccd4a63SDavid du Colombier 	Mntrpc *r;
3878ccd4a63SDavid du Colombier 	Walkqid *wq;
3888ccd4a63SDavid du Colombier 
3898ccd4a63SDavid du Colombier 	if(nc != nil)
3908ccd4a63SDavid du Colombier 		print("mntwalk: nc != nil\n");
3918ccd4a63SDavid du Colombier 	if(nname > MAXWELEM)
3928ccd4a63SDavid du Colombier 		error("devmnt: too many name elements");
3938ccd4a63SDavid du Colombier 	alloc = 0;
3948ccd4a63SDavid du Colombier 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
3958ccd4a63SDavid du Colombier 	if(waserror()){
3968ccd4a63SDavid du Colombier 		if(alloc && wq->clone!=nil)
3978ccd4a63SDavid du Colombier 			cclose(wq->clone);
3988ccd4a63SDavid du Colombier 		free(wq);
3998ccd4a63SDavid du Colombier 		return nil;
4008ccd4a63SDavid du Colombier 	}
4018ccd4a63SDavid du Colombier 
4028ccd4a63SDavid du Colombier 	alloc = 0;
4038ccd4a63SDavid du Colombier 	m = mntchk(c);
4048ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
4058ccd4a63SDavid du Colombier 	if(nc == nil){
4068ccd4a63SDavid du Colombier 		nc = devclone(c);
4078ccd4a63SDavid du Colombier 		/*
4088ccd4a63SDavid du Colombier 		 * Until the other side accepts this fid, we can't mntclose it.
4098ccd4a63SDavid du Colombier 		 * Therefore set type to 0 for now; rootclose is known to be safe.
4108ccd4a63SDavid du Colombier 		 */
4118ccd4a63SDavid du Colombier 		nc->type = 0;
4128ccd4a63SDavid du Colombier 		alloc = 1;
4138ccd4a63SDavid du Colombier 	}
4148ccd4a63SDavid du Colombier 	wq->clone = nc;
4158ccd4a63SDavid du Colombier 
4168ccd4a63SDavid du Colombier 	if(waserror()) {
4178ccd4a63SDavid du Colombier 		mntfree(r);
4188ccd4a63SDavid du Colombier 		nexterror();
4198ccd4a63SDavid du Colombier 	}
4208ccd4a63SDavid du Colombier 	r->request.type = Twalk;
4218ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
4228ccd4a63SDavid du Colombier 	r->request.newfid = nc->fid;
4238ccd4a63SDavid du Colombier 	r->request.nwname = nname;
4248ccd4a63SDavid du Colombier 	memmove(r->request.wname, name, nname*sizeof(char*));
4258ccd4a63SDavid du Colombier 
4268ccd4a63SDavid du Colombier 	mountrpc(m, r);
4278ccd4a63SDavid du Colombier 
4288ccd4a63SDavid du Colombier 	if(r->reply.nwqid > nname)
4298ccd4a63SDavid du Colombier 		error("too many QIDs returned by walk");
4308ccd4a63SDavid du Colombier 	if(r->reply.nwqid < nname){
4318ccd4a63SDavid du Colombier 		if(alloc)
4328ccd4a63SDavid du Colombier 			cclose(nc);
4338ccd4a63SDavid du Colombier 		wq->clone = nil;
4348ccd4a63SDavid du Colombier 		if(r->reply.nwqid == 0){
4358ccd4a63SDavid du Colombier 			free(wq);
4368ccd4a63SDavid du Colombier 			wq = nil;
4378ccd4a63SDavid du Colombier 			goto Return;
4388ccd4a63SDavid du Colombier 		}
4398ccd4a63SDavid du Colombier 	}
4408ccd4a63SDavid du Colombier 
4418ccd4a63SDavid du Colombier 	/* move new fid onto mnt device and update its qid */
4428ccd4a63SDavid du Colombier 	if(wq->clone != nil){
4438ccd4a63SDavid du Colombier 		if(wq->clone != c){
4448ccd4a63SDavid du Colombier 			wq->clone->type = c->type;
4458ccd4a63SDavid du Colombier 			wq->clone->mchan = c->mchan;
4468ccd4a63SDavid du Colombier 			incref(&c->mchan->ref);
4478ccd4a63SDavid du Colombier 		}
4488ccd4a63SDavid du Colombier 		if(r->reply.nwqid > 0)
4498ccd4a63SDavid du Colombier 			wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
4508ccd4a63SDavid du Colombier 	}
4518ccd4a63SDavid du Colombier 	wq->nqid = r->reply.nwqid;
4528ccd4a63SDavid du Colombier 	for(i=0; i<wq->nqid; i++)
4538ccd4a63SDavid du Colombier 		wq->qid[i] = r->reply.wqid[i];
4548ccd4a63SDavid du Colombier 
4558ccd4a63SDavid du Colombier     Return:
4568ccd4a63SDavid du Colombier 	poperror();
4578ccd4a63SDavid du Colombier 	mntfree(r);
4588ccd4a63SDavid du Colombier 	poperror();
4598ccd4a63SDavid du Colombier 	return wq;
4608ccd4a63SDavid du Colombier }
4618ccd4a63SDavid du Colombier 
4628ccd4a63SDavid du Colombier static int
mntstat(Chan * c,uchar * dp,int n)4638ccd4a63SDavid du Colombier mntstat(Chan *c, uchar *dp, int n)
4648ccd4a63SDavid du Colombier {
4658ccd4a63SDavid du Colombier 	Mnt *m;
4668ccd4a63SDavid du Colombier 	Mntrpc *r;
4678ccd4a63SDavid du Colombier 
4688ccd4a63SDavid du Colombier 	if(n < BIT16SZ)
4698ccd4a63SDavid du Colombier 		error(Eshortstat);
4708ccd4a63SDavid du Colombier 	m = mntchk(c);
4718ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
4728ccd4a63SDavid du Colombier 	if(waserror()) {
4738ccd4a63SDavid du Colombier 		mntfree(r);
4748ccd4a63SDavid du Colombier 		nexterror();
4758ccd4a63SDavid du Colombier 	}
4768ccd4a63SDavid du Colombier 	r->request.type = Tstat;
4778ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
4788ccd4a63SDavid du Colombier 	mountrpc(m, r);
4798ccd4a63SDavid du Colombier 
4808ccd4a63SDavid du Colombier /* r->reply.nstat is 16 bits
4818ccd4a63SDavid du Colombier 	if(r->reply.nstat >= 1<<16)
4828ccd4a63SDavid du Colombier 		error("returned stat buffer count too large");
4838ccd4a63SDavid du Colombier */
4848ccd4a63SDavid du Colombier 
4858ccd4a63SDavid du Colombier 	if(r->reply.nstat > n){
4868ccd4a63SDavid du Colombier 		/*
4878ccd4a63SDavid du Colombier 		 * 12/31/2002 RSC
4888ccd4a63SDavid du Colombier 		 *
4898ccd4a63SDavid du Colombier 		 * This should be nstat-2, which is the first two
4908ccd4a63SDavid du Colombier 		 * bytes of the stat buffer.  But dirstat and dirfstat
4918ccd4a63SDavid du Colombier 		 * depended on getting the full nstat (they didn't
4928ccd4a63SDavid du Colombier 		 * add BIT16SZ themselves).  I fixed dirstat and dirfstat
4938ccd4a63SDavid du Colombier 		 * but am leaving this unchanged for now.  After a
4948ccd4a63SDavid du Colombier 		 * few months, once enough of the relevant binaries
4958ccd4a63SDavid du Colombier 		 * have been recompiled for other reasons, we can
4968ccd4a63SDavid du Colombier 		 * change this to nstat-2.  Devstat gets this right
4978ccd4a63SDavid du Colombier 		 * (via convD2M).
4988ccd4a63SDavid du Colombier 		 */
4998ccd4a63SDavid du Colombier 		/* doesn't fit; just patch the count and return */
5008ccd4a63SDavid du Colombier 		PBIT16((uchar*)dp, r->reply.nstat);
5018ccd4a63SDavid du Colombier 		n = BIT16SZ;
5028ccd4a63SDavid du Colombier 	}else{
5038ccd4a63SDavid du Colombier 		n = r->reply.nstat;
5048ccd4a63SDavid du Colombier 		memmove(dp, r->reply.stat, n);
5058ccd4a63SDavid du Colombier 		validstat(dp, n);
5068ccd4a63SDavid du Colombier 		mntdirfix(dp, c);
5078ccd4a63SDavid du Colombier 	}
5088ccd4a63SDavid du Colombier 	poperror();
5098ccd4a63SDavid du Colombier 	mntfree(r);
5108ccd4a63SDavid du Colombier 	return n;
5118ccd4a63SDavid du Colombier }
5128ccd4a63SDavid du Colombier 
5138ccd4a63SDavid du Colombier static Chan*
mntopencreate(int type,Chan * c,char * name,int omode,ulong perm)5148ccd4a63SDavid du Colombier mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
5158ccd4a63SDavid du Colombier {
5168ccd4a63SDavid du Colombier 	Mnt *m;
5178ccd4a63SDavid du Colombier 	Mntrpc *r;
5188ccd4a63SDavid du Colombier 
5198ccd4a63SDavid du Colombier 	m = mntchk(c);
5208ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
5218ccd4a63SDavid du Colombier 	if(waserror()) {
5228ccd4a63SDavid du Colombier 		mntfree(r);
5238ccd4a63SDavid du Colombier 		nexterror();
5248ccd4a63SDavid du Colombier 	}
5258ccd4a63SDavid du Colombier 	r->request.type = type;
5268ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
5278ccd4a63SDavid du Colombier 	r->request.mode = omode;
5288ccd4a63SDavid du Colombier 	if(type == Tcreate){
5298ccd4a63SDavid du Colombier 		r->request.perm = perm;
5308ccd4a63SDavid du Colombier 		r->request.name = name;
5318ccd4a63SDavid du Colombier 	}
5328ccd4a63SDavid du Colombier 	mountrpc(m, r);
5338ccd4a63SDavid du Colombier 
5348ccd4a63SDavid du Colombier 	c->qid = r->reply.qid;
5358ccd4a63SDavid du Colombier 	c->offset = 0;
5368ccd4a63SDavid du Colombier 	c->mode = openmode(omode);
5378ccd4a63SDavid du Colombier 	c->iounit = r->reply.iounit;
5388ccd4a63SDavid du Colombier 	if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
5398ccd4a63SDavid du Colombier 		c->iounit = m->msize-IOHDRSZ;
5408ccd4a63SDavid du Colombier 	c->flag |= COPEN;
5418ccd4a63SDavid du Colombier 	poperror();
5428ccd4a63SDavid du Colombier 	mntfree(r);
5438ccd4a63SDavid du Colombier 
5448ccd4a63SDavid du Colombier 	if(c->flag & CCACHE)
5458ccd4a63SDavid du Colombier 		copen(c);
5468ccd4a63SDavid du Colombier 
5478ccd4a63SDavid du Colombier 	return c;
5488ccd4a63SDavid du Colombier }
5498ccd4a63SDavid du Colombier 
5508ccd4a63SDavid du Colombier static Chan*
mntopen(Chan * c,int omode)5518ccd4a63SDavid du Colombier mntopen(Chan *c, int omode)
5528ccd4a63SDavid du Colombier {
5538ccd4a63SDavid du Colombier 	return mntopencreate(Topen, c, nil, omode, 0);
5548ccd4a63SDavid du Colombier }
5558ccd4a63SDavid du Colombier 
5568ccd4a63SDavid du Colombier static void
mntcreate(Chan * c,char * name,int omode,ulong perm)5578ccd4a63SDavid du Colombier mntcreate(Chan *c, char *name, int omode, ulong perm)
5588ccd4a63SDavid du Colombier {
5598ccd4a63SDavid du Colombier 	mntopencreate(Tcreate, c, name, omode, perm);
5608ccd4a63SDavid du Colombier }
5618ccd4a63SDavid du Colombier 
5628ccd4a63SDavid du Colombier static void
mntclunk(Chan * c,int t)5638ccd4a63SDavid du Colombier mntclunk(Chan *c, int t)
5648ccd4a63SDavid du Colombier {
5658ccd4a63SDavid du Colombier 	Mnt *m;
5668ccd4a63SDavid du Colombier 	Mntrpc *r;
5678ccd4a63SDavid du Colombier 
5688ccd4a63SDavid du Colombier 	m = mntchk(c);
5698ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
5708ccd4a63SDavid du Colombier 	if(waserror()){
5718ccd4a63SDavid du Colombier 		mntfree(r);
5728ccd4a63SDavid du Colombier 		nexterror();
5738ccd4a63SDavid du Colombier 	}
5748ccd4a63SDavid du Colombier 
5758ccd4a63SDavid du Colombier 	r->request.type = t;
5768ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
5778ccd4a63SDavid du Colombier 	mountrpc(m, r);
5788ccd4a63SDavid du Colombier 	mntfree(r);
5798ccd4a63SDavid du Colombier 	poperror();
5808ccd4a63SDavid du Colombier }
5818ccd4a63SDavid du Colombier 
5828ccd4a63SDavid du Colombier void
muxclose(Mnt * m)5838ccd4a63SDavid du Colombier muxclose(Mnt *m)
5848ccd4a63SDavid du Colombier {
5858ccd4a63SDavid du Colombier 	Mntrpc *q, *r;
5868ccd4a63SDavid du Colombier 
5878ccd4a63SDavid du Colombier 	for(q = m->queue; q; q = r) {
5888ccd4a63SDavid du Colombier 		r = q->list;
5898ccd4a63SDavid du Colombier 		mntfree(q);
5908ccd4a63SDavid du Colombier 	}
5918ccd4a63SDavid du Colombier 	m->id = 0;
5928ccd4a63SDavid du Colombier 	free(m->version);
5938ccd4a63SDavid du Colombier 	m->version = nil;
5948ccd4a63SDavid du Colombier 	mntpntfree(m);
5958ccd4a63SDavid du Colombier }
5968ccd4a63SDavid du Colombier 
5978ccd4a63SDavid du Colombier void
mntpntfree(Mnt * m)5988ccd4a63SDavid du Colombier mntpntfree(Mnt *m)
5998ccd4a63SDavid du Colombier {
6008ccd4a63SDavid du Colombier 	Mnt *f, **l;
6018ccd4a63SDavid du Colombier 	Queue *q;
6028ccd4a63SDavid du Colombier 
6038ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
6048ccd4a63SDavid du Colombier 	l = &mntalloc.list;
6058ccd4a63SDavid du Colombier 	for(f = *l; f; f = f->list) {
6068ccd4a63SDavid du Colombier 		if(f == m) {
6078ccd4a63SDavid du Colombier 			*l = m->list;
6088ccd4a63SDavid du Colombier 			break;
6098ccd4a63SDavid du Colombier 		}
6108ccd4a63SDavid du Colombier 		l = &f->list;
6118ccd4a63SDavid du Colombier 	}
6128ccd4a63SDavid du Colombier 	m->list = mntalloc.mntfree;
6138ccd4a63SDavid du Colombier 	mntalloc.mntfree = m;
6148ccd4a63SDavid du Colombier 	q = m->q;
6158ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
6168ccd4a63SDavid du Colombier 
6178ccd4a63SDavid du Colombier 	qfree(q);
6188ccd4a63SDavid du Colombier }
6198ccd4a63SDavid du Colombier 
6208ccd4a63SDavid du Colombier static void
mntclose(Chan * c)6218ccd4a63SDavid du Colombier mntclose(Chan *c)
6228ccd4a63SDavid du Colombier {
6238ccd4a63SDavid du Colombier 	mntclunk(c, Tclunk);
6248ccd4a63SDavid du Colombier }
6258ccd4a63SDavid du Colombier 
6268ccd4a63SDavid du Colombier static void
mntremove(Chan * c)6278ccd4a63SDavid du Colombier mntremove(Chan *c)
6288ccd4a63SDavid du Colombier {
6298ccd4a63SDavid du Colombier 	mntclunk(c, Tremove);
6308ccd4a63SDavid du Colombier }
6318ccd4a63SDavid du Colombier 
6328ccd4a63SDavid du Colombier static int
mntwstat(Chan * c,uchar * dp,int n)6338ccd4a63SDavid du Colombier mntwstat(Chan *c, uchar *dp, int n)
6348ccd4a63SDavid du Colombier {
6358ccd4a63SDavid du Colombier 	Mnt *m;
6368ccd4a63SDavid du Colombier 	Mntrpc *r;
6378ccd4a63SDavid du Colombier 
6388ccd4a63SDavid du Colombier 	m = mntchk(c);
6398ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
6408ccd4a63SDavid du Colombier 	if(waserror()) {
6418ccd4a63SDavid du Colombier 		mntfree(r);
6428ccd4a63SDavid du Colombier 		nexterror();
6438ccd4a63SDavid du Colombier 	}
6448ccd4a63SDavid du Colombier 	r->request.type = Twstat;
6458ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
6468ccd4a63SDavid du Colombier 	r->request.nstat = n;
6478ccd4a63SDavid du Colombier 	r->request.stat = dp;
6488ccd4a63SDavid du Colombier 	mountrpc(m, r);
6498ccd4a63SDavid du Colombier 	poperror();
6508ccd4a63SDavid du Colombier 	mntfree(r);
6518ccd4a63SDavid du Colombier 	return n;
6528ccd4a63SDavid du Colombier }
6538ccd4a63SDavid du Colombier 
6548ccd4a63SDavid du Colombier static long
mntread(Chan * c,void * buf,long n,vlong off)6558ccd4a63SDavid du Colombier mntread(Chan *c, void *buf, long n, vlong off)
6568ccd4a63SDavid du Colombier {
6578ccd4a63SDavid du Colombier 	uchar *p, *e;
6588ccd4a63SDavid du Colombier 	int nc, cache, isdir, dirlen;
6598ccd4a63SDavid du Colombier 
6608ccd4a63SDavid du Colombier 	isdir = 0;
6618ccd4a63SDavid du Colombier 	cache = c->flag & CCACHE;
6628ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR) {
6638ccd4a63SDavid du Colombier 		cache = 0;
6648ccd4a63SDavid du Colombier 		isdir = 1;
6658ccd4a63SDavid du Colombier 	}
6668ccd4a63SDavid du Colombier 
6678ccd4a63SDavid du Colombier 	p = buf;
6688ccd4a63SDavid du Colombier 	if(cache) {
6698ccd4a63SDavid du Colombier 		nc = cread(c, buf, n, off);
6708ccd4a63SDavid du Colombier 		if(nc > 0) {
6718ccd4a63SDavid du Colombier 			n -= nc;
6728ccd4a63SDavid du Colombier 			if(n == 0)
6738ccd4a63SDavid du Colombier 				return nc;
6748ccd4a63SDavid du Colombier 			p += nc;
6758ccd4a63SDavid du Colombier 			off += nc;
6768ccd4a63SDavid du Colombier 		}
6778ccd4a63SDavid du Colombier 		n = mntrdwr(Tread, c, p, n, off);
6788ccd4a63SDavid du Colombier 		cupdate(c, p, n, off);
6798ccd4a63SDavid du Colombier 		return n + nc;
6808ccd4a63SDavid du Colombier 	}
6818ccd4a63SDavid du Colombier 
6828ccd4a63SDavid du Colombier 	n = mntrdwr(Tread, c, buf, n, off);
6838ccd4a63SDavid du Colombier 	if(isdir) {
6848ccd4a63SDavid du Colombier 		for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
6858ccd4a63SDavid du Colombier 			dirlen = BIT16SZ+GBIT16(p);
6868ccd4a63SDavid du Colombier 			if(p+dirlen > e)
6878ccd4a63SDavid du Colombier 				break;
6888ccd4a63SDavid du Colombier 			validstat(p, dirlen);
6898ccd4a63SDavid du Colombier 			mntdirfix(p, c);
6908ccd4a63SDavid du Colombier 		}
6918ccd4a63SDavid du Colombier 		if(p != e)
6928ccd4a63SDavid du Colombier 			error(Esbadstat);
6938ccd4a63SDavid du Colombier 	}
6948ccd4a63SDavid du Colombier 	return n;
6958ccd4a63SDavid du Colombier }
6968ccd4a63SDavid du Colombier 
6978ccd4a63SDavid du Colombier static long
mntwrite(Chan * c,void * buf,long n,vlong off)6988ccd4a63SDavid du Colombier mntwrite(Chan *c, void *buf, long n, vlong off)
6998ccd4a63SDavid du Colombier {
7008ccd4a63SDavid du Colombier 	return mntrdwr(Twrite, c, buf, n, off);
7018ccd4a63SDavid du Colombier }
7028ccd4a63SDavid du Colombier 
7038ccd4a63SDavid du Colombier long
mntrdwr(int type,Chan * c,void * buf,long n,vlong off)7048ccd4a63SDavid du Colombier mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
7058ccd4a63SDavid du Colombier {
7068ccd4a63SDavid du Colombier 	Mnt *m;
7078ccd4a63SDavid du Colombier  	Mntrpc *r;
7088ccd4a63SDavid du Colombier 	char *uba;
7098ccd4a63SDavid du Colombier 	int cache;
7108ccd4a63SDavid du Colombier 	ulong cnt, nr, nreq;
7118ccd4a63SDavid du Colombier 
7128ccd4a63SDavid du Colombier 	m = mntchk(c);
7138ccd4a63SDavid du Colombier 	uba = buf;
7148ccd4a63SDavid du Colombier 	cnt = 0;
7158ccd4a63SDavid du Colombier 	cache = c->flag & CCACHE;
7168ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR)
7178ccd4a63SDavid du Colombier 		cache = 0;
7188ccd4a63SDavid du Colombier 	for(;;) {
7198ccd4a63SDavid du Colombier 		r = mntralloc(c, m->msize);
7208ccd4a63SDavid du Colombier 		if(waserror()) {
7218ccd4a63SDavid du Colombier 			mntfree(r);
7228ccd4a63SDavid du Colombier 			nexterror();
7238ccd4a63SDavid du Colombier 		}
7248ccd4a63SDavid du Colombier 		r->request.type = type;
7258ccd4a63SDavid du Colombier 		r->request.fid = c->fid;
7268ccd4a63SDavid du Colombier 		r->request.offset = off;
7278ccd4a63SDavid du Colombier 		r->request.data = uba;
7288ccd4a63SDavid du Colombier 		nr = n;
7298ccd4a63SDavid du Colombier 		if(nr > m->msize-IOHDRSZ)
7308ccd4a63SDavid du Colombier 			nr = m->msize-IOHDRSZ;
7318ccd4a63SDavid du Colombier 		r->request.count = nr;
7328ccd4a63SDavid du Colombier 		mountrpc(m, r);
7338ccd4a63SDavid du Colombier 		nreq = r->request.count;
7348ccd4a63SDavid du Colombier 		nr = r->reply.count;
7358ccd4a63SDavid du Colombier 		if(nr > nreq)
7368ccd4a63SDavid du Colombier 			nr = nreq;
7378ccd4a63SDavid du Colombier 
7388ccd4a63SDavid du Colombier 		if(type == Tread)
7398ccd4a63SDavid du Colombier 			r->b = bl2mem((uchar*)uba, r->b, nr);
7408ccd4a63SDavid du Colombier 		else if(cache)
7418ccd4a63SDavid du Colombier 			cwrite(c, (uchar*)uba, nr, off);
7428ccd4a63SDavid du Colombier 
7438ccd4a63SDavid du Colombier 		poperror();
7448ccd4a63SDavid du Colombier 		mntfree(r);
7458ccd4a63SDavid du Colombier 		off += nr;
7468ccd4a63SDavid du Colombier 		uba += nr;
7478ccd4a63SDavid du Colombier 		cnt += nr;
7488ccd4a63SDavid du Colombier 		n -= nr;
7498ccd4a63SDavid du Colombier 		if(nr != nreq || n == 0)
7508ccd4a63SDavid du Colombier 			break;
7518ccd4a63SDavid du Colombier 	}
7528ccd4a63SDavid du Colombier 	return cnt;
7538ccd4a63SDavid du Colombier }
7548ccd4a63SDavid du Colombier 
7558ccd4a63SDavid du Colombier void
mountrpc(Mnt * m,Mntrpc * r)7568ccd4a63SDavid du Colombier mountrpc(Mnt *m, Mntrpc *r)
7578ccd4a63SDavid du Colombier {
7588ccd4a63SDavid du Colombier 	char *sn, *cn;
7598ccd4a63SDavid du Colombier 	int t;
7608ccd4a63SDavid du Colombier 
7618ccd4a63SDavid du Colombier 	r->reply.tag = 0;
7628ccd4a63SDavid du Colombier 	r->reply.type = Tmax;	/* can't ever be a valid message type */
7638ccd4a63SDavid du Colombier 
7648ccd4a63SDavid du Colombier 	mountio(m, r);
7658ccd4a63SDavid du Colombier 
7668ccd4a63SDavid du Colombier 	t = r->reply.type;
7678ccd4a63SDavid du Colombier 	switch(t) {
7688ccd4a63SDavid du Colombier 	case Rerror:
7698ccd4a63SDavid du Colombier 		error(r->reply.ename);
7708ccd4a63SDavid du Colombier 	case Rflush:
7718ccd4a63SDavid du Colombier 		error(Eintr);
7728ccd4a63SDavid du Colombier 	default:
7738ccd4a63SDavid du Colombier 		if(t == r->request.type+1)
7748ccd4a63SDavid du Colombier 			break;
7758ccd4a63SDavid du Colombier 		sn = "?";
7768ccd4a63SDavid du Colombier 		if(m->c->name != nil)
7778ccd4a63SDavid du Colombier 			sn = m->c->name->s;
7788ccd4a63SDavid du Colombier 		cn = "?";
7798ccd4a63SDavid du Colombier 		if(r->c != nil && r->c->name != nil)
7808ccd4a63SDavid du Colombier 			cn = r->c->name->s;
7818ccd4a63SDavid du Colombier 		print("mnt: proc %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n",
7828ccd4a63SDavid du Colombier 			up->pid, sn, cn,
7838ccd4a63SDavid du Colombier 			r, r->request.tag, r->request.fid, r->request.type,
7848ccd4a63SDavid du Colombier 			r->reply.type, r->reply.tag);
7858ccd4a63SDavid du Colombier 		error(Emountrpc);
7868ccd4a63SDavid du Colombier 	}
7878ccd4a63SDavid du Colombier }
7888ccd4a63SDavid du Colombier 
7898ccd4a63SDavid du Colombier void
mountio(Mnt * m,Mntrpc * r)7908ccd4a63SDavid du Colombier mountio(Mnt *m, Mntrpc *r)
7918ccd4a63SDavid du Colombier {
7928ccd4a63SDavid du Colombier 	int n;
7938ccd4a63SDavid du Colombier 
7948ccd4a63SDavid du Colombier 	while(waserror()) {
7958ccd4a63SDavid du Colombier 		if(m->rip == up)
7968ccd4a63SDavid du Colombier 			mntgate(m);
7978ccd4a63SDavid du Colombier 		if(strcmp(up->errstr, Eintr) != 0){
7988ccd4a63SDavid du Colombier 			mntflushfree(m, r);
7998ccd4a63SDavid du Colombier 			nexterror();
8008ccd4a63SDavid du Colombier 		}
8018ccd4a63SDavid du Colombier 		r = mntflushalloc(r, m->msize);
8028ccd4a63SDavid du Colombier 	}
8038ccd4a63SDavid du Colombier 
8048ccd4a63SDavid du Colombier 	lock(&m->lk);
8058ccd4a63SDavid du Colombier 	r->m = m;
8068ccd4a63SDavid du Colombier 	r->list = m->queue;
8078ccd4a63SDavid du Colombier 	m->queue = r;
8088ccd4a63SDavid du Colombier 	unlock(&m->lk);
8098ccd4a63SDavid du Colombier 
8108ccd4a63SDavid du Colombier 	/* Transmit a file system rpc */
8118ccd4a63SDavid du Colombier 	if(m->msize == 0)
8128ccd4a63SDavid du Colombier 		panic("msize");
8138ccd4a63SDavid du Colombier 	n = convS2M(&r->request, r->rpc, m->msize);
8148ccd4a63SDavid du Colombier 	if(n < 0)
8158ccd4a63SDavid du Colombier 		panic("bad message type in mountio");
8168ccd4a63SDavid du Colombier 	if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
8178ccd4a63SDavid du Colombier 		error(Emountrpc);
8188ccd4a63SDavid du Colombier 	r->stime = fastticks(nil);
8198ccd4a63SDavid du Colombier 	r->reqlen = n;
8208ccd4a63SDavid du Colombier 
8218ccd4a63SDavid du Colombier 	/* Gate readers onto the mount point one at a time */
8228ccd4a63SDavid du Colombier 	for(;;) {
8238ccd4a63SDavid du Colombier 		lock(&m->lk);
8248ccd4a63SDavid du Colombier 		if(m->rip == 0)
8258ccd4a63SDavid du Colombier 			break;
8268ccd4a63SDavid du Colombier 		unlock(&m->lk);
8278ccd4a63SDavid du Colombier 		sleep(&r->r, rpcattn, r);
8288ccd4a63SDavid du Colombier 		if(r->done){
8298ccd4a63SDavid du Colombier 			poperror();
8308ccd4a63SDavid du Colombier 			mntflushfree(m, r);
8318ccd4a63SDavid du Colombier 			return;
8328ccd4a63SDavid du Colombier 		}
8338ccd4a63SDavid du Colombier 	}
8348ccd4a63SDavid du Colombier 	m->rip = up;
8358ccd4a63SDavid du Colombier 	unlock(&m->lk);
8368ccd4a63SDavid du Colombier 	while(r->done == 0) {
8378ccd4a63SDavid du Colombier 		if(mntrpcread(m, r) < 0)
8388ccd4a63SDavid du Colombier 			error(Emountrpc);
8398ccd4a63SDavid du Colombier 		mountmux(m, r);
8408ccd4a63SDavid du Colombier 	}
8418ccd4a63SDavid du Colombier 	mntgate(m);
8428ccd4a63SDavid du Colombier 	poperror();
8438ccd4a63SDavid du Colombier 	mntflushfree(m, r);
8448ccd4a63SDavid du Colombier }
8458ccd4a63SDavid du Colombier 
8468ccd4a63SDavid du Colombier static int
doread(Mnt * m,int len)8478ccd4a63SDavid du Colombier doread(Mnt *m, int len)
8488ccd4a63SDavid du Colombier {
8498ccd4a63SDavid du Colombier 	Block *b;
8508ccd4a63SDavid du Colombier 
8518ccd4a63SDavid du Colombier 	while(qlen(m->q) < len){
8528ccd4a63SDavid du Colombier 		b = devtab[m->c->type]->bread(m->c, m->msize, 0);
8538ccd4a63SDavid du Colombier 		if(b == nil)
8548ccd4a63SDavid du Colombier 			return -1;
8558ccd4a63SDavid du Colombier 		if(BLEN(b) == 0){
8568ccd4a63SDavid du Colombier 			freeblist(b);
8578ccd4a63SDavid du Colombier 			return -1;
8588ccd4a63SDavid du Colombier 		}
8598ccd4a63SDavid du Colombier 		qaddlist(m->q, b);
8608ccd4a63SDavid du Colombier 	}
8618ccd4a63SDavid du Colombier 	return 0;
8628ccd4a63SDavid du Colombier }
8638ccd4a63SDavid du Colombier 
8648ccd4a63SDavid du Colombier int
mntrpcread(Mnt * m,Mntrpc * r)8658ccd4a63SDavid du Colombier mntrpcread(Mnt *m, Mntrpc *r)
8668ccd4a63SDavid du Colombier {
8678ccd4a63SDavid du Colombier 	int i, t, len, hlen;
8688ccd4a63SDavid du Colombier 	Block *b, **l, *nb;
8698ccd4a63SDavid du Colombier 
8708ccd4a63SDavid du Colombier 	r->reply.type = 0;
8718ccd4a63SDavid du Colombier 	r->reply.tag = 0;
8728ccd4a63SDavid du Colombier 
8738ccd4a63SDavid du Colombier 	/* read at least length, type, and tag and pullup to a single block */
8748ccd4a63SDavid du Colombier 	if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
8758ccd4a63SDavid du Colombier 		return -1;
8768ccd4a63SDavid du Colombier 	nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
8778ccd4a63SDavid du Colombier 
8788ccd4a63SDavid du Colombier 	/* read in the rest of the message, avoid rediculous (for now) message sizes */
8798ccd4a63SDavid du Colombier 	len = GBIT32(nb->rp);
8808ccd4a63SDavid du Colombier 	if(len > m->msize){
8818ccd4a63SDavid du Colombier 		qdiscard(m->q, qlen(m->q));
8828ccd4a63SDavid du Colombier 		return -1;
8838ccd4a63SDavid du Colombier 	}
8848ccd4a63SDavid du Colombier 	if(doread(m, len) < 0)
8858ccd4a63SDavid du Colombier 		return -1;
8868ccd4a63SDavid du Colombier 
8878ccd4a63SDavid du Colombier 	/* pullup the header (i.e. everything except data) */
8888ccd4a63SDavid du Colombier 	t = nb->rp[BIT32SZ];
8898ccd4a63SDavid du Colombier 	switch(t){
8908ccd4a63SDavid du Colombier 	case Rread:
8918ccd4a63SDavid du Colombier 		hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
8928ccd4a63SDavid du Colombier 		break;
8938ccd4a63SDavid du Colombier 	default:
8948ccd4a63SDavid du Colombier 		hlen = len;
8958ccd4a63SDavid du Colombier 		break;
8968ccd4a63SDavid du Colombier 	}
8978ccd4a63SDavid du Colombier 	nb = pullupqueue(m->q, hlen);
8988ccd4a63SDavid du Colombier 
8998ccd4a63SDavid du Colombier 	if(convM2S(nb->rp, len, &r->reply) <= 0){
9008ccd4a63SDavid du Colombier 		/* bad message, dump it */
9018ccd4a63SDavid du Colombier 		print("mntrpcread: convM2S failed\n");
9028ccd4a63SDavid du Colombier 		qdiscard(m->q, len);
9038ccd4a63SDavid du Colombier 		return -1;
9048ccd4a63SDavid du Colombier 	}
9058ccd4a63SDavid du Colombier 
9068ccd4a63SDavid du Colombier 	/* hang the data off of the fcall struct */
9078ccd4a63SDavid du Colombier 	l = &r->b;
9088ccd4a63SDavid du Colombier 	*l = nil;
9098ccd4a63SDavid du Colombier 	do {
9108ccd4a63SDavid du Colombier 		b = qremove(m->q);
9118ccd4a63SDavid du Colombier 		if(hlen > 0){
9128ccd4a63SDavid du Colombier 			b->rp += hlen;
9138ccd4a63SDavid du Colombier 			len -= hlen;
9148ccd4a63SDavid du Colombier 			hlen = 0;
9158ccd4a63SDavid du Colombier 		}
9168ccd4a63SDavid du Colombier 		i = BLEN(b);
9178ccd4a63SDavid du Colombier 		if(i <= len){
9188ccd4a63SDavid du Colombier 			len -= i;
9198ccd4a63SDavid du Colombier 			*l = b;
9208ccd4a63SDavid du Colombier 			l = &(b->next);
9218ccd4a63SDavid du Colombier 		} else {
9228ccd4a63SDavid du Colombier 			/* split block and put unused bit back */
9238ccd4a63SDavid du Colombier 			nb = allocb(i-len);
9248ccd4a63SDavid du Colombier 			memmove(nb->wp, b->rp+len, i-len);
9258ccd4a63SDavid du Colombier 			b->wp = b->rp+len;
9268ccd4a63SDavid du Colombier 			nb->wp += i-len;
9278ccd4a63SDavid du Colombier 			qputback(m->q, nb);
9288ccd4a63SDavid du Colombier 			*l = b;
9298ccd4a63SDavid du Colombier 			return 0;
9308ccd4a63SDavid du Colombier 		}
9318ccd4a63SDavid du Colombier 	}while(len > 0);
9328ccd4a63SDavid du Colombier 
9338ccd4a63SDavid du Colombier 	return 0;
9348ccd4a63SDavid du Colombier }
9358ccd4a63SDavid du Colombier 
9368ccd4a63SDavid du Colombier void
mntgate(Mnt * m)9378ccd4a63SDavid du Colombier mntgate(Mnt *m)
9388ccd4a63SDavid du Colombier {
9398ccd4a63SDavid du Colombier 	Mntrpc *q;
9408ccd4a63SDavid du Colombier 
9418ccd4a63SDavid du Colombier 	lock(&m->lk);
9428ccd4a63SDavid du Colombier 	m->rip = 0;
9438ccd4a63SDavid du Colombier 	for(q = m->queue; q; q = q->list) {
9448ccd4a63SDavid du Colombier 		if(q->done == 0)
9458ccd4a63SDavid du Colombier 		if(wakeup(&q->r))
9468ccd4a63SDavid du Colombier 			break;
9478ccd4a63SDavid du Colombier 	}
9488ccd4a63SDavid du Colombier 	unlock(&m->lk);
9498ccd4a63SDavid du Colombier }
9508ccd4a63SDavid du Colombier 
9518ccd4a63SDavid du Colombier void
mountmux(Mnt * m,Mntrpc * r)9528ccd4a63SDavid du Colombier mountmux(Mnt *m, Mntrpc *r)
9538ccd4a63SDavid du Colombier {
9548ccd4a63SDavid du Colombier 	Mntrpc **l, *q;
9558ccd4a63SDavid du Colombier 
9568ccd4a63SDavid du Colombier 	lock(&m->lk);
9578ccd4a63SDavid du Colombier 	l = &m->queue;
9588ccd4a63SDavid du Colombier 	for(q = *l; q; q = q->list) {
9598ccd4a63SDavid du Colombier 		/* look for a reply to a message */
9608ccd4a63SDavid du Colombier 		if(q->request.tag == r->reply.tag) {
9618ccd4a63SDavid du Colombier 			*l = q->list;
9628ccd4a63SDavid du Colombier 			if(q != r) {
9638ccd4a63SDavid du Colombier 				/*
9648ccd4a63SDavid du Colombier 				 * Completed someone else.
9658ccd4a63SDavid du Colombier 				 * Trade pointers to receive buffer.
9668ccd4a63SDavid du Colombier 				 */
9678ccd4a63SDavid du Colombier 				q->reply = r->reply;
9688ccd4a63SDavid du Colombier 				q->b = r->b;
9698ccd4a63SDavid du Colombier 				r->b = nil;
9708ccd4a63SDavid du Colombier 			}
9718ccd4a63SDavid du Colombier 			q->done = 1;
9728ccd4a63SDavid du Colombier 			unlock(&m->lk);
973ec59a3ddSDavid du Colombier 			if(mntstats != 0)
9748ccd4a63SDavid du Colombier 				(*mntstats)(q->request.type,
9758ccd4a63SDavid du Colombier 					m->c, q->stime,
9768ccd4a63SDavid du Colombier 					q->reqlen + r->replen);
9778ccd4a63SDavid du Colombier 			if(q != r)
9788ccd4a63SDavid du Colombier 				wakeup(&q->r);
9798ccd4a63SDavid du Colombier 			return;
9808ccd4a63SDavid du Colombier 		}
9818ccd4a63SDavid du Colombier 		l = &q->list;
9828ccd4a63SDavid du Colombier 	}
9838ccd4a63SDavid du Colombier 	unlock(&m->lk);
9848ccd4a63SDavid du Colombier 	print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
9858ccd4a63SDavid du Colombier }
9868ccd4a63SDavid du Colombier 
9878ccd4a63SDavid du Colombier /*
9888ccd4a63SDavid du Colombier  * Create a new flush request and chain the previous
9898ccd4a63SDavid du Colombier  * requests from it
9908ccd4a63SDavid du Colombier  */
9918ccd4a63SDavid du Colombier Mntrpc*
mntflushalloc(Mntrpc * r,ulong iounit)9928ccd4a63SDavid du Colombier mntflushalloc(Mntrpc *r, ulong iounit)
9938ccd4a63SDavid du Colombier {
9948ccd4a63SDavid du Colombier 	Mntrpc *fr;
9958ccd4a63SDavid du Colombier 
9968ccd4a63SDavid du Colombier 	fr = mntralloc(0, iounit);
9978ccd4a63SDavid du Colombier 
9988ccd4a63SDavid du Colombier 	fr->request.type = Tflush;
9998ccd4a63SDavid du Colombier 	if(r->request.type == Tflush)
10008ccd4a63SDavid du Colombier 		fr->request.oldtag = r->request.oldtag;
10018ccd4a63SDavid du Colombier 	else
10028ccd4a63SDavid du Colombier 		fr->request.oldtag = r->request.tag;
10038ccd4a63SDavid du Colombier 	fr->flushed = r;
10048ccd4a63SDavid du Colombier 
10058ccd4a63SDavid du Colombier 	return fr;
10068ccd4a63SDavid du Colombier }
10078ccd4a63SDavid du Colombier 
10088ccd4a63SDavid du Colombier /*
10098ccd4a63SDavid du Colombier  *  Free a chain of flushes.  Remove each unanswered
10108ccd4a63SDavid du Colombier  *  flush and the original message from the unanswered
10118ccd4a63SDavid du Colombier  *  request queue.  Mark the original message as done
10128ccd4a63SDavid du Colombier  *  and if it hasn't been answered set the reply to to
10138ccd4a63SDavid du Colombier  *  Rflush.
10148ccd4a63SDavid du Colombier  */
10158ccd4a63SDavid du Colombier void
mntflushfree(Mnt * m,Mntrpc * r)10168ccd4a63SDavid du Colombier mntflushfree(Mnt *m, Mntrpc *r)
10178ccd4a63SDavid du Colombier {
10188ccd4a63SDavid du Colombier 	Mntrpc *fr;
10198ccd4a63SDavid du Colombier 
10208ccd4a63SDavid du Colombier 	while(r){
10218ccd4a63SDavid du Colombier 		fr = r->flushed;
10228ccd4a63SDavid du Colombier 		if(!r->done){
10238ccd4a63SDavid du Colombier 			r->reply.type = Rflush;
10248ccd4a63SDavid du Colombier 			mntqrm(m, r);
10258ccd4a63SDavid du Colombier 		}
10268ccd4a63SDavid du Colombier 		if(fr)
10278ccd4a63SDavid du Colombier 			mntfree(r);
10288ccd4a63SDavid du Colombier 		r = fr;
10298ccd4a63SDavid du Colombier 	}
10308ccd4a63SDavid du Colombier }
10318ccd4a63SDavid du Colombier 
10328ccd4a63SDavid du Colombier int
alloctag(void)10338ccd4a63SDavid du Colombier alloctag(void)
10348ccd4a63SDavid du Colombier {
10358ccd4a63SDavid du Colombier 	int i, j;
10368ccd4a63SDavid du Colombier 	ulong v;
10378ccd4a63SDavid du Colombier 
10388ccd4a63SDavid du Colombier 	for(i = 0; i < NMASK; i++){
10398ccd4a63SDavid du Colombier 		v = mntalloc.tagmask[i];
1040ec59a3ddSDavid du Colombier 		if(v == ~0)
10418ccd4a63SDavid du Colombier 			continue;
10428ccd4a63SDavid du Colombier 		for(j = 0; j < 1<<TAGSHIFT; j++)
10438ccd4a63SDavid du Colombier 			if((v & (1<<j)) == 0){
10448ccd4a63SDavid du Colombier 				mntalloc.tagmask[i] |= 1<<j;
10458ccd4a63SDavid du Colombier 				return (i<<TAGSHIFT) + j;
10468ccd4a63SDavid du Colombier 			}
10478ccd4a63SDavid du Colombier 	}
10488ccd4a63SDavid du Colombier 	panic("no friggin tags left");
10498ccd4a63SDavid du Colombier 	return NOTAG;
10508ccd4a63SDavid du Colombier }
10518ccd4a63SDavid du Colombier 
10528ccd4a63SDavid du Colombier void
freetag(int t)10538ccd4a63SDavid du Colombier freetag(int t)
10548ccd4a63SDavid du Colombier {
10558ccd4a63SDavid du Colombier 	mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
10568ccd4a63SDavid du Colombier }
10578ccd4a63SDavid du Colombier 
10588ccd4a63SDavid du Colombier Mntrpc*
mntralloc(Chan * c,ulong msize)10598ccd4a63SDavid du Colombier mntralloc(Chan *c, ulong msize)
10608ccd4a63SDavid du Colombier {
10618ccd4a63SDavid du Colombier 	Mntrpc *new;
10628ccd4a63SDavid du Colombier 
10638ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
10648ccd4a63SDavid du Colombier 	new = mntalloc.rpcfree;
10658ccd4a63SDavid du Colombier 	if(new == nil){
10668ccd4a63SDavid du Colombier 		new = malloc(sizeof(Mntrpc));
10678ccd4a63SDavid du Colombier 		if(new == nil) {
10688ccd4a63SDavid du Colombier 			unlock(&mntalloc.lk);
10698ccd4a63SDavid du Colombier 			exhausted("mount rpc header");
10708ccd4a63SDavid du Colombier 		}
10718ccd4a63SDavid du Colombier 		/*
10728ccd4a63SDavid du Colombier 		 * The header is split from the data buffer as
10738ccd4a63SDavid du Colombier 		 * mountmux may swap the buffer with another header.
10748ccd4a63SDavid du Colombier 		 */
10758ccd4a63SDavid du Colombier 		new->rpc = mallocz(msize, 0);
10768ccd4a63SDavid du Colombier 		if(new->rpc == nil){
10778ccd4a63SDavid du Colombier 			free(new);
10788ccd4a63SDavid du Colombier 			unlock(&mntalloc.lk);
10798ccd4a63SDavid du Colombier 			exhausted("mount rpc buffer");
10808ccd4a63SDavid du Colombier 		}
10818ccd4a63SDavid du Colombier 		new->rpclen = msize;
10828ccd4a63SDavid du Colombier 		new->request.tag = alloctag();
10838ccd4a63SDavid du Colombier 	}
10848ccd4a63SDavid du Colombier 	else {
10858ccd4a63SDavid du Colombier 		mntalloc.rpcfree = new->list;
10868ccd4a63SDavid du Colombier 		mntalloc.nrpcfree--;
10878ccd4a63SDavid du Colombier 		if(new->rpclen < msize){
10888ccd4a63SDavid du Colombier 			free(new->rpc);
10898ccd4a63SDavid du Colombier 			new->rpc = mallocz(msize, 0);
10908ccd4a63SDavid du Colombier 			if(new->rpc == nil){
10918ccd4a63SDavid du Colombier 				free(new);
10928ccd4a63SDavid du Colombier 				mntalloc.nrpcused--;
10938ccd4a63SDavid du Colombier 				unlock(&mntalloc.lk);
10948ccd4a63SDavid du Colombier 				exhausted("mount rpc buffer");
10958ccd4a63SDavid du Colombier 			}
10968ccd4a63SDavid du Colombier 			new->rpclen = msize;
10978ccd4a63SDavid du Colombier 		}
10988ccd4a63SDavid du Colombier 	}
10998ccd4a63SDavid du Colombier 	mntalloc.nrpcused++;
11008ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
11018ccd4a63SDavid du Colombier 	new->c = c;
11028ccd4a63SDavid du Colombier 	new->done = 0;
11038ccd4a63SDavid du Colombier 	new->flushed = nil;
11048ccd4a63SDavid du Colombier 	new->b = nil;
11058ccd4a63SDavid du Colombier 	return new;
11068ccd4a63SDavid du Colombier }
11078ccd4a63SDavid du Colombier 
11088ccd4a63SDavid du Colombier void
mntfree(Mntrpc * r)11098ccd4a63SDavid du Colombier mntfree(Mntrpc *r)
11108ccd4a63SDavid du Colombier {
11118ccd4a63SDavid du Colombier 	if(r->b != nil)
11128ccd4a63SDavid du Colombier 		freeblist(r->b);
11138ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
11148ccd4a63SDavid du Colombier 	if(mntalloc.nrpcfree >= 10){
11158ccd4a63SDavid du Colombier 		free(r->rpc);
11168ccd4a63SDavid du Colombier 		free(r);
11178ccd4a63SDavid du Colombier 		freetag(r->request.tag);
11188ccd4a63SDavid du Colombier 	}
11198ccd4a63SDavid du Colombier 	else{
11208ccd4a63SDavid du Colombier 		r->list = mntalloc.rpcfree;
11218ccd4a63SDavid du Colombier 		mntalloc.rpcfree = r;
11228ccd4a63SDavid du Colombier 		mntalloc.nrpcfree++;
11238ccd4a63SDavid du Colombier 	}
11248ccd4a63SDavid du Colombier 	mntalloc.nrpcused--;
11258ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
11268ccd4a63SDavid du Colombier }
11278ccd4a63SDavid du Colombier 
11288ccd4a63SDavid du Colombier void
mntqrm(Mnt * m,Mntrpc * r)11298ccd4a63SDavid du Colombier mntqrm(Mnt *m, Mntrpc *r)
11308ccd4a63SDavid du Colombier {
11318ccd4a63SDavid du Colombier 	Mntrpc **l, *f;
11328ccd4a63SDavid du Colombier 
11338ccd4a63SDavid du Colombier 	lock(&m->lk);
11348ccd4a63SDavid du Colombier 	r->done = 1;
11358ccd4a63SDavid du Colombier 
11368ccd4a63SDavid du Colombier 	l = &m->queue;
11378ccd4a63SDavid du Colombier 	for(f = *l; f; f = f->list) {
11388ccd4a63SDavid du Colombier 		if(f == r) {
11398ccd4a63SDavid du Colombier 			*l = r->list;
11408ccd4a63SDavid du Colombier 			break;
11418ccd4a63SDavid du Colombier 		}
11428ccd4a63SDavid du Colombier 		l = &f->list;
11438ccd4a63SDavid du Colombier 	}
11448ccd4a63SDavid du Colombier 	unlock(&m->lk);
11458ccd4a63SDavid du Colombier }
11468ccd4a63SDavid du Colombier 
11478ccd4a63SDavid du Colombier Mnt*
mntchk(Chan * c)11488ccd4a63SDavid du Colombier mntchk(Chan *c)
11498ccd4a63SDavid du Colombier {
11508ccd4a63SDavid du Colombier 	Mnt *m;
11518ccd4a63SDavid du Colombier 
11528ccd4a63SDavid du Colombier 	/* This routine is mostly vestiges of prior lives; now it's just sanity checking */
11538ccd4a63SDavid du Colombier 
11548ccd4a63SDavid du Colombier 	if(c->mchan == nil)
11558ccd4a63SDavid du Colombier 		panic("mntchk 1: nil mchan c %s\n", c2name(c));
11568ccd4a63SDavid du Colombier 
11578ccd4a63SDavid du Colombier 	m = c->mchan->mux;
11588ccd4a63SDavid du Colombier 
11598ccd4a63SDavid du Colombier 	if(m == nil)
11608ccd4a63SDavid du Colombier 		print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan));
11618ccd4a63SDavid du Colombier 
11628ccd4a63SDavid du Colombier 	/*
11638ccd4a63SDavid du Colombier 	 * Was it closed and reused (was error(Eshutdown); now, it can't happen)
11648ccd4a63SDavid du Colombier 	 */
11658ccd4a63SDavid du Colombier 	if(m->id == 0 || m->id >= c->dev)
11668ccd4a63SDavid du Colombier 		panic("mntchk 3: can't happen");
11678ccd4a63SDavid du Colombier 
11688ccd4a63SDavid du Colombier 	return m;
11698ccd4a63SDavid du Colombier }
11708ccd4a63SDavid du Colombier 
11718ccd4a63SDavid du Colombier /*
11728ccd4a63SDavid du Colombier  * Rewrite channel type and dev for in-flight data to
11738ccd4a63SDavid du Colombier  * reflect local values.  These entries are known to be
11748ccd4a63SDavid du Colombier  * the first two in the Dir encoding after the count.
11758ccd4a63SDavid du Colombier  */
11768ccd4a63SDavid du Colombier void
mntdirfix(uchar * dirbuf,Chan * c)11778ccd4a63SDavid du Colombier mntdirfix(uchar *dirbuf, Chan *c)
11788ccd4a63SDavid du Colombier {
11798ccd4a63SDavid du Colombier 	uint r;
11808ccd4a63SDavid du Colombier 
11818ccd4a63SDavid du Colombier 	r = devtab[c->type]->dc;
11828ccd4a63SDavid du Colombier 	dirbuf += BIT16SZ;	/* skip count */
11838ccd4a63SDavid du Colombier 	PBIT16(dirbuf, r);
11848ccd4a63SDavid du Colombier 	dirbuf += BIT16SZ;
11858ccd4a63SDavid du Colombier 	PBIT32(dirbuf, c->dev);
11868ccd4a63SDavid du Colombier }
11878ccd4a63SDavid du Colombier 
11888ccd4a63SDavid du Colombier int
rpcattn(void * v)11898ccd4a63SDavid du Colombier rpcattn(void *v)
11908ccd4a63SDavid du Colombier {
11918ccd4a63SDavid du Colombier 	Mntrpc *r;
11928ccd4a63SDavid du Colombier 
11938ccd4a63SDavid du Colombier 	r = v;
11948ccd4a63SDavid du Colombier 	return r->done || r->m->rip == 0;
11958ccd4a63SDavid du Colombier }
11968ccd4a63SDavid du Colombier 
11978ccd4a63SDavid du Colombier Dev mntdevtab = {
11988ccd4a63SDavid du Colombier 	'M',
11998ccd4a63SDavid du Colombier 	"mnt",
12008ccd4a63SDavid du Colombier 
12018ccd4a63SDavid du Colombier 	mntreset,
12028ccd4a63SDavid du Colombier 	devinit,
12038ccd4a63SDavid du Colombier 	devshutdown,
12048ccd4a63SDavid du Colombier 	mntattach,
12058ccd4a63SDavid du Colombier 	mntwalk,
12068ccd4a63SDavid du Colombier 	mntstat,
12078ccd4a63SDavid du Colombier 	mntopen,
12088ccd4a63SDavid du Colombier 	mntcreate,
12098ccd4a63SDavid du Colombier 	mntclose,
12108ccd4a63SDavid du Colombier 	mntread,
12118ccd4a63SDavid du Colombier 	devbread,
12128ccd4a63SDavid du Colombier 	mntwrite,
12138ccd4a63SDavid du Colombier 	devbwrite,
12148ccd4a63SDavid du Colombier 	mntremove,
12158ccd4a63SDavid du Colombier 	mntwstat,
12168ccd4a63SDavid du Colombier };
1217