xref: /plan9-contrib/sys/src/cmd/unix/drawterm/kern/devmnt.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include	"u.h"
2*8ccd4a63SDavid du Colombier #include	"lib.h"
3*8ccd4a63SDavid du Colombier #include	"dat.h"
4*8ccd4a63SDavid du Colombier #include	"fns.h"
5*8ccd4a63SDavid du Colombier #include	"error.h"
6*8ccd4a63SDavid du Colombier 
7*8ccd4a63SDavid du Colombier /*
8*8ccd4a63SDavid du Colombier  * References are managed as follows:
9*8ccd4a63SDavid du Colombier  * The channel to the server - a network connection or pipe - has one
10*8ccd4a63SDavid du Colombier  * reference for every Chan open on the server.  The server channel has
11*8ccd4a63SDavid du Colombier  * c->mux set to the Mnt used for muxing control to that server.  Mnts
12*8ccd4a63SDavid du Colombier  * have no reference count; they go away when c goes away.
13*8ccd4a63SDavid du Colombier  * Each channel derived from the mount point has mchan set to c,
14*8ccd4a63SDavid du Colombier  * and increfs/decrefs mchan to manage references on the server
15*8ccd4a63SDavid du Colombier  * connection.
16*8ccd4a63SDavid du Colombier  */
17*8ccd4a63SDavid du Colombier 
18*8ccd4a63SDavid du Colombier #define MAXRPC (IOHDRSZ+8192)
19*8ccd4a63SDavid du Colombier 
20*8ccd4a63SDavid du Colombier struct Mntrpc
21*8ccd4a63SDavid du Colombier {
22*8ccd4a63SDavid du Colombier 	Chan*	c;		/* Channel for whom we are working */
23*8ccd4a63SDavid du Colombier 	Mntrpc*	list;		/* Free/pending list */
24*8ccd4a63SDavid du Colombier 	Fcall	request;	/* Outgoing file system protocol message */
25*8ccd4a63SDavid du Colombier 	Fcall 	reply;		/* Incoming reply */
26*8ccd4a63SDavid du Colombier 	Mnt*	m;		/* Mount device during rpc */
27*8ccd4a63SDavid du Colombier 	Rendez	r;		/* Place to hang out */
28*8ccd4a63SDavid du Colombier 	uchar*	rpc;		/* I/O Data buffer */
29*8ccd4a63SDavid du Colombier 	uint		rpclen;	/* len of buffer */
30*8ccd4a63SDavid du Colombier 	Block	*b;		/* reply blocks */
31*8ccd4a63SDavid du Colombier 	char	done;		/* Rpc completed */
32*8ccd4a63SDavid du Colombier 	uvlong	stime;		/* start time for mnt statistics */
33*8ccd4a63SDavid du Colombier 	ulong	reqlen;		/* request length for mnt statistics */
34*8ccd4a63SDavid du Colombier 	ulong	replen;		/* reply length for mnt statistics */
35*8ccd4a63SDavid du Colombier 	Mntrpc*	flushed;	/* message this one flushes */
36*8ccd4a63SDavid du Colombier };
37*8ccd4a63SDavid du Colombier 
38*8ccd4a63SDavid du Colombier enum
39*8ccd4a63SDavid du Colombier {
40*8ccd4a63SDavid du Colombier 	TAGSHIFT = 5,			/* ulong has to be 32 bits */
41*8ccd4a63SDavid du Colombier 	TAGMASK = (1<<TAGSHIFT)-1,
42*8ccd4a63SDavid du Colombier 	NMASK = (64*1024)>>TAGSHIFT,
43*8ccd4a63SDavid du Colombier };
44*8ccd4a63SDavid du Colombier 
45*8ccd4a63SDavid du Colombier struct Mntalloc
46*8ccd4a63SDavid du Colombier {
47*8ccd4a63SDavid du Colombier 	Lock lk;
48*8ccd4a63SDavid du Colombier 	Mnt*	list;		/* Mount devices in use */
49*8ccd4a63SDavid du Colombier 	Mnt*	mntfree;	/* Free list */
50*8ccd4a63SDavid du Colombier 	Mntrpc*	rpcfree;
51*8ccd4a63SDavid du Colombier 	int	nrpcfree;
52*8ccd4a63SDavid du Colombier 	int	nrpcused;
53*8ccd4a63SDavid du Colombier 	ulong	id;
54*8ccd4a63SDavid du Colombier 	ulong	tagmask[NMASK];
55*8ccd4a63SDavid du Colombier }mntalloc;
56*8ccd4a63SDavid du Colombier 
57*8ccd4a63SDavid du Colombier void	mattach(Mnt*, Chan*, char*);
58*8ccd4a63SDavid du Colombier Mnt*	mntchk(Chan*);
59*8ccd4a63SDavid du Colombier void	mntdirfix(uchar*, Chan*);
60*8ccd4a63SDavid du Colombier Mntrpc*	mntflushalloc(Mntrpc*, ulong);
61*8ccd4a63SDavid du Colombier void	mntflushfree(Mnt*, Mntrpc*);
62*8ccd4a63SDavid du Colombier void	mntfree(Mntrpc*);
63*8ccd4a63SDavid du Colombier void	mntgate(Mnt*);
64*8ccd4a63SDavid du Colombier void	mntpntfree(Mnt*);
65*8ccd4a63SDavid du Colombier void	mntqrm(Mnt*, Mntrpc*);
66*8ccd4a63SDavid du Colombier Mntrpc*	mntralloc(Chan*, ulong);
67*8ccd4a63SDavid du Colombier long	mntrdwr(int, Chan*, void*, long, vlong);
68*8ccd4a63SDavid du Colombier int	mntrpcread(Mnt*, Mntrpc*);
69*8ccd4a63SDavid du Colombier void	mountio(Mnt*, Mntrpc*);
70*8ccd4a63SDavid du Colombier void	mountmux(Mnt*, Mntrpc*);
71*8ccd4a63SDavid du Colombier void	mountrpc(Mnt*, Mntrpc*);
72*8ccd4a63SDavid du Colombier int	rpcattn(void*);
73*8ccd4a63SDavid du Colombier Chan*	mntchan(void);
74*8ccd4a63SDavid du Colombier 
75*8ccd4a63SDavid du Colombier char	Esbadstat[] = "invalid directory entry received from server";
76*8ccd4a63SDavid du Colombier char Enoversion[] = "version not established for mount channel";
77*8ccd4a63SDavid du Colombier 
78*8ccd4a63SDavid du Colombier 
79*8ccd4a63SDavid du Colombier void (*mntstats)(int, Chan*, uvlong, ulong);
80*8ccd4a63SDavid du Colombier 
81*8ccd4a63SDavid du Colombier static void
82*8ccd4a63SDavid du Colombier mntreset(void)
83*8ccd4a63SDavid du Colombier {
84*8ccd4a63SDavid du Colombier 	mntalloc.id = 1;
85*8ccd4a63SDavid du Colombier 	mntalloc.tagmask[0] = 1;			/* don't allow 0 as a tag */
86*8ccd4a63SDavid du Colombier 	mntalloc.tagmask[NMASK-1] = 0x80000000UL;	/* don't allow NOTAG */
87*8ccd4a63SDavid du Colombier 	fmtinstall('F', fcallfmt);
88*8ccd4a63SDavid du Colombier 	fmtinstall('D', dirfmt);
89*8ccd4a63SDavid du Colombier /* We can't install %M since eipfmt does and is used in the kernel [sape] */
90*8ccd4a63SDavid du Colombier 
91*8ccd4a63SDavid du Colombier 	cinit();
92*8ccd4a63SDavid du Colombier }
93*8ccd4a63SDavid du Colombier 
94*8ccd4a63SDavid du Colombier /*
95*8ccd4a63SDavid du Colombier  * Version is not multiplexed: message sent only once per connection.
96*8ccd4a63SDavid du Colombier  */
97*8ccd4a63SDavid du Colombier long
98*8ccd4a63SDavid du Colombier mntversion(Chan *c, char *version, int msize, int returnlen)
99*8ccd4a63SDavid du Colombier {
100*8ccd4a63SDavid du Colombier 	Fcall f;
101*8ccd4a63SDavid du Colombier 	uchar *msg;
102*8ccd4a63SDavid du Colombier 	Mnt *m;
103*8ccd4a63SDavid du Colombier 	char *v;
104*8ccd4a63SDavid du Colombier 	long k, l;
105*8ccd4a63SDavid du Colombier 	uvlong oo;
106*8ccd4a63SDavid du Colombier 	char buf[128];
107*8ccd4a63SDavid du Colombier 
108*8ccd4a63SDavid du Colombier 	qlock(&c->umqlock);	/* make sure no one else does this until we've established ourselves */
109*8ccd4a63SDavid du Colombier 	if(waserror()){
110*8ccd4a63SDavid du Colombier 		qunlock(&c->umqlock);
111*8ccd4a63SDavid du Colombier 		nexterror();
112*8ccd4a63SDavid du Colombier 	}
113*8ccd4a63SDavid du Colombier 
114*8ccd4a63SDavid du Colombier 	/* defaults */
115*8ccd4a63SDavid du Colombier 	if(msize == 0)
116*8ccd4a63SDavid du Colombier 		msize = MAXRPC;
117*8ccd4a63SDavid du Colombier 	if(msize > c->iounit && c->iounit != 0)
118*8ccd4a63SDavid du Colombier 		msize = c->iounit;
119*8ccd4a63SDavid du Colombier 	v = version;
120*8ccd4a63SDavid du Colombier 	if(v == nil || v[0] == '\0')
121*8ccd4a63SDavid du Colombier 		v = VERSION9P;
122*8ccd4a63SDavid du Colombier 
123*8ccd4a63SDavid du Colombier 	/* validity */
124*8ccd4a63SDavid du Colombier 	if(msize < 0)
125*8ccd4a63SDavid du Colombier 		error("bad iounit in version call");
126*8ccd4a63SDavid du Colombier 	if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
127*8ccd4a63SDavid du Colombier 		error("bad 9P version specification");
128*8ccd4a63SDavid du Colombier 
129*8ccd4a63SDavid du Colombier 	m = c->mux;
130*8ccd4a63SDavid du Colombier 
131*8ccd4a63SDavid du Colombier 	if(m != nil){
132*8ccd4a63SDavid du Colombier 		qunlock(&c->umqlock);
133*8ccd4a63SDavid du Colombier 		poperror();
134*8ccd4a63SDavid du Colombier 
135*8ccd4a63SDavid du Colombier 		strecpy(buf, buf+sizeof buf, m->version);
136*8ccd4a63SDavid du Colombier 		k = strlen(buf);
137*8ccd4a63SDavid du Colombier 		if(strncmp(buf, v, k) != 0){
138*8ccd4a63SDavid du Colombier 			snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
139*8ccd4a63SDavid du Colombier 			error(buf);
140*8ccd4a63SDavid du Colombier 		}
141*8ccd4a63SDavid du Colombier 		if(returnlen > 0){
142*8ccd4a63SDavid du Colombier 			if(returnlen < k)
143*8ccd4a63SDavid du Colombier 				error(Eshort);
144*8ccd4a63SDavid du Colombier 			memmove(version, buf, k);
145*8ccd4a63SDavid du Colombier 		}
146*8ccd4a63SDavid du Colombier 		return k;
147*8ccd4a63SDavid du Colombier 	}
148*8ccd4a63SDavid du Colombier 
149*8ccd4a63SDavid du Colombier 	f.type = Tversion;
150*8ccd4a63SDavid du Colombier 	f.tag = NOTAG;
151*8ccd4a63SDavid du Colombier 	f.msize = msize;
152*8ccd4a63SDavid du Colombier 	f.version = v;
153*8ccd4a63SDavid du Colombier 	msg = malloc(8192+IOHDRSZ);
154*8ccd4a63SDavid du Colombier 	if(msg == nil)
155*8ccd4a63SDavid du Colombier 		exhausted("version memory");
156*8ccd4a63SDavid du Colombier 	if(waserror()){
157*8ccd4a63SDavid du Colombier 		free(msg);
158*8ccd4a63SDavid du Colombier 		nexterror();
159*8ccd4a63SDavid du Colombier 	}
160*8ccd4a63SDavid du Colombier 	k = convS2M(&f, msg, 8192+IOHDRSZ);
161*8ccd4a63SDavid du Colombier 	if(k == 0)
162*8ccd4a63SDavid du Colombier 		error("bad fversion conversion on send");
163*8ccd4a63SDavid du Colombier 
164*8ccd4a63SDavid du Colombier 	lock(&c->ref.lk);
165*8ccd4a63SDavid du Colombier 	oo = c->offset;
166*8ccd4a63SDavid du Colombier 	c->offset += k;
167*8ccd4a63SDavid du Colombier 	unlock(&c->ref.lk);
168*8ccd4a63SDavid du Colombier 
169*8ccd4a63SDavid du Colombier 	l = devtab[c->type]->write(c, msg, k, oo);
170*8ccd4a63SDavid du Colombier 
171*8ccd4a63SDavid du Colombier 	if(l < k){
172*8ccd4a63SDavid du Colombier 		lock(&c->ref.lk);
173*8ccd4a63SDavid du Colombier 		c->offset -= k - l;
174*8ccd4a63SDavid du Colombier 		unlock(&c->ref.lk);
175*8ccd4a63SDavid du Colombier 		error("short write in fversion");
176*8ccd4a63SDavid du Colombier 	}
177*8ccd4a63SDavid du Colombier 
178*8ccd4a63SDavid du Colombier 	/* message sent; receive and decode reply */
179*8ccd4a63SDavid du Colombier 	k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
180*8ccd4a63SDavid du Colombier 	if(k <= 0)
181*8ccd4a63SDavid du Colombier 		error("EOF receiving fversion reply");
182*8ccd4a63SDavid du Colombier 
183*8ccd4a63SDavid du Colombier 	lock(&c->ref.lk);
184*8ccd4a63SDavid du Colombier 	c->offset += k;
185*8ccd4a63SDavid du Colombier 	unlock(&c->ref.lk);
186*8ccd4a63SDavid du Colombier 
187*8ccd4a63SDavid du Colombier 	l = convM2S(msg, k, &f);
188*8ccd4a63SDavid du Colombier 	if(l != k)
189*8ccd4a63SDavid du Colombier 		error("bad fversion conversion on reply");
190*8ccd4a63SDavid du Colombier 	if(f.type != Rversion){
191*8ccd4a63SDavid du Colombier 		if(f.type == Rerror)
192*8ccd4a63SDavid du Colombier 			error(f.ename);
193*8ccd4a63SDavid du Colombier 		error("unexpected reply type in fversion");
194*8ccd4a63SDavid du Colombier 	}
195*8ccd4a63SDavid du Colombier 	if(f.msize > msize)
196*8ccd4a63SDavid du Colombier 		error("server tries to increase msize in fversion");
197*8ccd4a63SDavid du Colombier 	if(f.msize<256 || f.msize>1024*1024)
198*8ccd4a63SDavid du Colombier 		error("nonsense value of msize in fversion");
199*8ccd4a63SDavid du Colombier 	if(strncmp(f.version, v, strlen(f.version)) != 0)
200*8ccd4a63SDavid du Colombier 		error("bad 9P version returned from server");
201*8ccd4a63SDavid du Colombier 
202*8ccd4a63SDavid du Colombier 	/* now build Mnt associated with this connection */
203*8ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
204*8ccd4a63SDavid du Colombier 	m = mntalloc.mntfree;
205*8ccd4a63SDavid du Colombier 	if(m != 0)
206*8ccd4a63SDavid du Colombier 		mntalloc.mntfree = m->list;
207*8ccd4a63SDavid du Colombier 	else {
208*8ccd4a63SDavid du Colombier 		m = malloc(sizeof(Mnt));
209*8ccd4a63SDavid du Colombier 		if(m == 0) {
210*8ccd4a63SDavid du Colombier 			unlock(&mntalloc.lk);
211*8ccd4a63SDavid du Colombier 			exhausted("mount devices");
212*8ccd4a63SDavid du Colombier 		}
213*8ccd4a63SDavid du Colombier 	}
214*8ccd4a63SDavid du Colombier 	m->list = mntalloc.list;
215*8ccd4a63SDavid du Colombier 	mntalloc.list = m;
216*8ccd4a63SDavid du Colombier 	m->version = nil;
217*8ccd4a63SDavid du Colombier 	kstrdup(&m->version, f.version);
218*8ccd4a63SDavid du Colombier 	m->id = mntalloc.id++;
219*8ccd4a63SDavid du Colombier 	m->q = qopen(10*MAXRPC, 0, nil, nil);
220*8ccd4a63SDavid du Colombier 	m->msize = f.msize;
221*8ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
222*8ccd4a63SDavid du Colombier 
223*8ccd4a63SDavid du Colombier 	poperror();	/* msg */
224*8ccd4a63SDavid du Colombier 	free(msg);
225*8ccd4a63SDavid du Colombier 
226*8ccd4a63SDavid du Colombier 	lock(&m->lk);
227*8ccd4a63SDavid du Colombier 	m->queue = 0;
228*8ccd4a63SDavid du Colombier 	m->rip = 0;
229*8ccd4a63SDavid du Colombier 
230*8ccd4a63SDavid du Colombier 	c->flag |= CMSG;
231*8ccd4a63SDavid du Colombier 	c->mux = m;
232*8ccd4a63SDavid du Colombier 	m->c = c;
233*8ccd4a63SDavid du Colombier 	unlock(&m->lk);
234*8ccd4a63SDavid du Colombier 
235*8ccd4a63SDavid du Colombier 	poperror();	/* c */
236*8ccd4a63SDavid du Colombier 	qunlock(&c->umqlock);
237*8ccd4a63SDavid du Colombier 
238*8ccd4a63SDavid du Colombier 	k = strlen(f.version);
239*8ccd4a63SDavid du Colombier 	if(returnlen > 0){
240*8ccd4a63SDavid du Colombier 		if(returnlen < k)
241*8ccd4a63SDavid du Colombier 			error(Eshort);
242*8ccd4a63SDavid du Colombier 		memmove(version, f.version, k);
243*8ccd4a63SDavid du Colombier 	}
244*8ccd4a63SDavid du Colombier 
245*8ccd4a63SDavid du Colombier 	return k;
246*8ccd4a63SDavid du Colombier }
247*8ccd4a63SDavid du Colombier 
248*8ccd4a63SDavid du Colombier Chan*
249*8ccd4a63SDavid du Colombier mntauth(Chan *c, char *spec)
250*8ccd4a63SDavid du Colombier {
251*8ccd4a63SDavid du Colombier 	Mnt *m;
252*8ccd4a63SDavid du Colombier 	Mntrpc *r;
253*8ccd4a63SDavid du Colombier 
254*8ccd4a63SDavid du Colombier 	m = c->mux;
255*8ccd4a63SDavid du Colombier 
256*8ccd4a63SDavid du Colombier 	if(m == nil){
257*8ccd4a63SDavid du Colombier 		mntversion(c, VERSION9P, MAXRPC, 0);
258*8ccd4a63SDavid du Colombier 		m = c->mux;
259*8ccd4a63SDavid du Colombier 		if(m == nil)
260*8ccd4a63SDavid du Colombier 			error(Enoversion);
261*8ccd4a63SDavid du Colombier 	}
262*8ccd4a63SDavid du Colombier 
263*8ccd4a63SDavid du Colombier 	c = mntchan();
264*8ccd4a63SDavid du Colombier 	if(waserror()) {
265*8ccd4a63SDavid du Colombier 		/* Close must not be called since it will
266*8ccd4a63SDavid du Colombier 		 * call mnt recursively
267*8ccd4a63SDavid du Colombier 		 */
268*8ccd4a63SDavid du Colombier 		chanfree(c);
269*8ccd4a63SDavid du Colombier 		nexterror();
270*8ccd4a63SDavid du Colombier 	}
271*8ccd4a63SDavid du Colombier 
272*8ccd4a63SDavid du Colombier 	r = mntralloc(0, m->msize);
273*8ccd4a63SDavid du Colombier 
274*8ccd4a63SDavid du Colombier 	if(waserror()) {
275*8ccd4a63SDavid du Colombier 		mntfree(r);
276*8ccd4a63SDavid du Colombier 		nexterror();
277*8ccd4a63SDavid du Colombier 	}
278*8ccd4a63SDavid du Colombier 
279*8ccd4a63SDavid du Colombier 	r->request.type = Tauth;
280*8ccd4a63SDavid du Colombier 	r->request.afid = c->fid;
281*8ccd4a63SDavid du Colombier 	r->request.uname = up->user;
282*8ccd4a63SDavid du Colombier 	r->request.aname = spec;
283*8ccd4a63SDavid du Colombier 	mountrpc(m, r);
284*8ccd4a63SDavid du Colombier 
285*8ccd4a63SDavid du Colombier 	c->qid = r->reply.aqid;
286*8ccd4a63SDavid du Colombier 	c->mchan = m->c;
287*8ccd4a63SDavid du Colombier 	incref(&m->c->ref);
288*8ccd4a63SDavid du Colombier 	c->mqid = c->qid;
289*8ccd4a63SDavid du Colombier 	c->mode = ORDWR;
290*8ccd4a63SDavid du Colombier 
291*8ccd4a63SDavid du Colombier 	poperror();	/* r */
292*8ccd4a63SDavid du Colombier 	mntfree(r);
293*8ccd4a63SDavid du Colombier 
294*8ccd4a63SDavid du Colombier 	poperror();	/* c */
295*8ccd4a63SDavid du Colombier 
296*8ccd4a63SDavid du Colombier 	return c;
297*8ccd4a63SDavid du Colombier 
298*8ccd4a63SDavid du Colombier }
299*8ccd4a63SDavid du Colombier 
300*8ccd4a63SDavid du Colombier static Chan*
301*8ccd4a63SDavid du Colombier mntattach(char *muxattach)
302*8ccd4a63SDavid du Colombier {
303*8ccd4a63SDavid du Colombier 	Mnt *m;
304*8ccd4a63SDavid du Colombier 	Chan *c;
305*8ccd4a63SDavid du Colombier 	Mntrpc *r;
306*8ccd4a63SDavid du Colombier 	struct bogus{
307*8ccd4a63SDavid du Colombier 		Chan	*chan;
308*8ccd4a63SDavid du Colombier 		Chan	*authchan;
309*8ccd4a63SDavid du Colombier 		char	*spec;
310*8ccd4a63SDavid du Colombier 		int	flags;
311*8ccd4a63SDavid du Colombier 	}bogus;
312*8ccd4a63SDavid du Colombier 
313*8ccd4a63SDavid du Colombier 	bogus = *((struct bogus *)muxattach);
314*8ccd4a63SDavid du Colombier 	c = bogus.chan;
315*8ccd4a63SDavid du Colombier 
316*8ccd4a63SDavid du Colombier 	m = c->mux;
317*8ccd4a63SDavid du Colombier 
318*8ccd4a63SDavid du Colombier 	if(m == nil){
319*8ccd4a63SDavid du Colombier 		mntversion(c, nil, 0, 0);
320*8ccd4a63SDavid du Colombier 		m = c->mux;
321*8ccd4a63SDavid du Colombier 		if(m == nil)
322*8ccd4a63SDavid du Colombier 			error(Enoversion);
323*8ccd4a63SDavid du Colombier 	}
324*8ccd4a63SDavid du Colombier 
325*8ccd4a63SDavid du Colombier 	c = mntchan();
326*8ccd4a63SDavid du Colombier 	if(waserror()) {
327*8ccd4a63SDavid du Colombier 		/* Close must not be called since it will
328*8ccd4a63SDavid du Colombier 		 * call mnt recursively
329*8ccd4a63SDavid du Colombier 		 */
330*8ccd4a63SDavid du Colombier 		chanfree(c);
331*8ccd4a63SDavid du Colombier 		nexterror();
332*8ccd4a63SDavid du Colombier 	}
333*8ccd4a63SDavid du Colombier 
334*8ccd4a63SDavid du Colombier 	r = mntralloc(0, m->msize);
335*8ccd4a63SDavid du Colombier 
336*8ccd4a63SDavid du Colombier 	if(waserror()) {
337*8ccd4a63SDavid du Colombier 		mntfree(r);
338*8ccd4a63SDavid du Colombier 		nexterror();
339*8ccd4a63SDavid du Colombier 	}
340*8ccd4a63SDavid du Colombier 
341*8ccd4a63SDavid du Colombier 	r->request.type = Tattach;
342*8ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
343*8ccd4a63SDavid du Colombier 	if(bogus.authchan == nil)
344*8ccd4a63SDavid du Colombier 		r->request.afid = NOFID;
345*8ccd4a63SDavid du Colombier 	else
346*8ccd4a63SDavid du Colombier 		r->request.afid = bogus.authchan->fid;
347*8ccd4a63SDavid du Colombier 	r->request.uname = up->user;
348*8ccd4a63SDavid du Colombier 	r->request.aname = bogus.spec;
349*8ccd4a63SDavid du Colombier 	mountrpc(m, r);
350*8ccd4a63SDavid du Colombier 
351*8ccd4a63SDavid du Colombier 	c->qid = r->reply.qid;
352*8ccd4a63SDavid du Colombier 	c->mchan = m->c;
353*8ccd4a63SDavid du Colombier 	incref(&m->c->ref);
354*8ccd4a63SDavid du Colombier 	c->mqid = c->qid;
355*8ccd4a63SDavid du Colombier 
356*8ccd4a63SDavid du Colombier 	poperror();	/* r */
357*8ccd4a63SDavid du Colombier 	mntfree(r);
358*8ccd4a63SDavid du Colombier 
359*8ccd4a63SDavid du Colombier 	poperror();	/* c */
360*8ccd4a63SDavid du Colombier 
361*8ccd4a63SDavid du Colombier 	if(bogus.flags&MCACHE)
362*8ccd4a63SDavid du Colombier 		c->flag |= CCACHE;
363*8ccd4a63SDavid du Colombier 	return c;
364*8ccd4a63SDavid du Colombier }
365*8ccd4a63SDavid du Colombier 
366*8ccd4a63SDavid du Colombier Chan*
367*8ccd4a63SDavid du Colombier mntchan(void)
368*8ccd4a63SDavid du Colombier {
369*8ccd4a63SDavid du Colombier 	Chan *c;
370*8ccd4a63SDavid du Colombier 
371*8ccd4a63SDavid du Colombier 	c = devattach('M', 0);
372*8ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
373*8ccd4a63SDavid du Colombier 	c->dev = mntalloc.id++;
374*8ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
375*8ccd4a63SDavid du Colombier 
376*8ccd4a63SDavid du Colombier 	if(c->mchan)
377*8ccd4a63SDavid du Colombier 		panic("mntchan non-zero %p", c->mchan);
378*8ccd4a63SDavid du Colombier 	return c;
379*8ccd4a63SDavid du Colombier }
380*8ccd4a63SDavid du Colombier 
381*8ccd4a63SDavid du Colombier static Walkqid*
382*8ccd4a63SDavid du Colombier mntwalk(Chan *c, Chan *nc, char **name, int nname)
383*8ccd4a63SDavid du Colombier {
384*8ccd4a63SDavid du Colombier 	int i, alloc;
385*8ccd4a63SDavid du Colombier 	Mnt *m;
386*8ccd4a63SDavid du Colombier 	Mntrpc *r;
387*8ccd4a63SDavid du Colombier 	Walkqid *wq;
388*8ccd4a63SDavid du Colombier 
389*8ccd4a63SDavid du Colombier 	if(nc != nil)
390*8ccd4a63SDavid du Colombier 		print("mntwalk: nc != nil\n");
391*8ccd4a63SDavid du Colombier 	if(nname > MAXWELEM)
392*8ccd4a63SDavid du Colombier 		error("devmnt: too many name elements");
393*8ccd4a63SDavid du Colombier 	alloc = 0;
394*8ccd4a63SDavid du Colombier 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
395*8ccd4a63SDavid du Colombier 	if(waserror()){
396*8ccd4a63SDavid du Colombier 		if(alloc && wq->clone!=nil)
397*8ccd4a63SDavid du Colombier 			cclose(wq->clone);
398*8ccd4a63SDavid du Colombier 		free(wq);
399*8ccd4a63SDavid du Colombier 		return nil;
400*8ccd4a63SDavid du Colombier 	}
401*8ccd4a63SDavid du Colombier 
402*8ccd4a63SDavid du Colombier 	alloc = 0;
403*8ccd4a63SDavid du Colombier 	m = mntchk(c);
404*8ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
405*8ccd4a63SDavid du Colombier 	if(nc == nil){
406*8ccd4a63SDavid du Colombier 		nc = devclone(c);
407*8ccd4a63SDavid du Colombier 		/*
408*8ccd4a63SDavid du Colombier 		 * Until the other side accepts this fid, we can't mntclose it.
409*8ccd4a63SDavid du Colombier 		 * Therefore set type to 0 for now; rootclose is known to be safe.
410*8ccd4a63SDavid du Colombier 		 */
411*8ccd4a63SDavid du Colombier 		nc->type = 0;
412*8ccd4a63SDavid du Colombier 		alloc = 1;
413*8ccd4a63SDavid du Colombier 	}
414*8ccd4a63SDavid du Colombier 	wq->clone = nc;
415*8ccd4a63SDavid du Colombier 
416*8ccd4a63SDavid du Colombier 	if(waserror()) {
417*8ccd4a63SDavid du Colombier 		mntfree(r);
418*8ccd4a63SDavid du Colombier 		nexterror();
419*8ccd4a63SDavid du Colombier 	}
420*8ccd4a63SDavid du Colombier 	r->request.type = Twalk;
421*8ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
422*8ccd4a63SDavid du Colombier 	r->request.newfid = nc->fid;
423*8ccd4a63SDavid du Colombier 	r->request.nwname = nname;
424*8ccd4a63SDavid du Colombier 	memmove(r->request.wname, name, nname*sizeof(char*));
425*8ccd4a63SDavid du Colombier 
426*8ccd4a63SDavid du Colombier 	mountrpc(m, r);
427*8ccd4a63SDavid du Colombier 
428*8ccd4a63SDavid du Colombier 	if(r->reply.nwqid > nname)
429*8ccd4a63SDavid du Colombier 		error("too many QIDs returned by walk");
430*8ccd4a63SDavid du Colombier 	if(r->reply.nwqid < nname){
431*8ccd4a63SDavid du Colombier 		if(alloc)
432*8ccd4a63SDavid du Colombier 			cclose(nc);
433*8ccd4a63SDavid du Colombier 		wq->clone = nil;
434*8ccd4a63SDavid du Colombier 		if(r->reply.nwqid == 0){
435*8ccd4a63SDavid du Colombier 			free(wq);
436*8ccd4a63SDavid du Colombier 			wq = nil;
437*8ccd4a63SDavid du Colombier 			goto Return;
438*8ccd4a63SDavid du Colombier 		}
439*8ccd4a63SDavid du Colombier 	}
440*8ccd4a63SDavid du Colombier 
441*8ccd4a63SDavid du Colombier 	/* move new fid onto mnt device and update its qid */
442*8ccd4a63SDavid du Colombier 	if(wq->clone != nil){
443*8ccd4a63SDavid du Colombier 		if(wq->clone != c){
444*8ccd4a63SDavid du Colombier 			wq->clone->type = c->type;
445*8ccd4a63SDavid du Colombier 			wq->clone->mchan = c->mchan;
446*8ccd4a63SDavid du Colombier 			incref(&c->mchan->ref);
447*8ccd4a63SDavid du Colombier 		}
448*8ccd4a63SDavid du Colombier 		if(r->reply.nwqid > 0)
449*8ccd4a63SDavid du Colombier 			wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
450*8ccd4a63SDavid du Colombier 	}
451*8ccd4a63SDavid du Colombier 	wq->nqid = r->reply.nwqid;
452*8ccd4a63SDavid du Colombier 	for(i=0; i<wq->nqid; i++)
453*8ccd4a63SDavid du Colombier 		wq->qid[i] = r->reply.wqid[i];
454*8ccd4a63SDavid du Colombier 
455*8ccd4a63SDavid du Colombier     Return:
456*8ccd4a63SDavid du Colombier 	poperror();
457*8ccd4a63SDavid du Colombier 	mntfree(r);
458*8ccd4a63SDavid du Colombier 	poperror();
459*8ccd4a63SDavid du Colombier 	return wq;
460*8ccd4a63SDavid du Colombier }
461*8ccd4a63SDavid du Colombier 
462*8ccd4a63SDavid du Colombier static int
463*8ccd4a63SDavid du Colombier mntstat(Chan *c, uchar *dp, int n)
464*8ccd4a63SDavid du Colombier {
465*8ccd4a63SDavid du Colombier 	Mnt *m;
466*8ccd4a63SDavid du Colombier 	Mntrpc *r;
467*8ccd4a63SDavid du Colombier 
468*8ccd4a63SDavid du Colombier 	if(n < BIT16SZ)
469*8ccd4a63SDavid du Colombier 		error(Eshortstat);
470*8ccd4a63SDavid du Colombier 	m = mntchk(c);
471*8ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
472*8ccd4a63SDavid du Colombier 	if(waserror()) {
473*8ccd4a63SDavid du Colombier 		mntfree(r);
474*8ccd4a63SDavid du Colombier 		nexterror();
475*8ccd4a63SDavid du Colombier 	}
476*8ccd4a63SDavid du Colombier 	r->request.type = Tstat;
477*8ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
478*8ccd4a63SDavid du Colombier 	mountrpc(m, r);
479*8ccd4a63SDavid du Colombier 
480*8ccd4a63SDavid du Colombier /* r->reply.nstat is 16 bits
481*8ccd4a63SDavid du Colombier 	if(r->reply.nstat >= 1<<16)
482*8ccd4a63SDavid du Colombier 		error("returned stat buffer count too large");
483*8ccd4a63SDavid du Colombier */
484*8ccd4a63SDavid du Colombier 
485*8ccd4a63SDavid du Colombier 	if(r->reply.nstat > n){
486*8ccd4a63SDavid du Colombier 		/*
487*8ccd4a63SDavid du Colombier 		 * 12/31/2002 RSC
488*8ccd4a63SDavid du Colombier 		 *
489*8ccd4a63SDavid du Colombier 		 * This should be nstat-2, which is the first two
490*8ccd4a63SDavid du Colombier 		 * bytes of the stat buffer.  But dirstat and dirfstat
491*8ccd4a63SDavid du Colombier 		 * depended on getting the full nstat (they didn't
492*8ccd4a63SDavid du Colombier 		 * add BIT16SZ themselves).  I fixed dirstat and dirfstat
493*8ccd4a63SDavid du Colombier 		 * but am leaving this unchanged for now.  After a
494*8ccd4a63SDavid du Colombier 		 * few months, once enough of the relevant binaries
495*8ccd4a63SDavid du Colombier 		 * have been recompiled for other reasons, we can
496*8ccd4a63SDavid du Colombier 		 * change this to nstat-2.  Devstat gets this right
497*8ccd4a63SDavid du Colombier 		 * (via convD2M).
498*8ccd4a63SDavid du Colombier 		 */
499*8ccd4a63SDavid du Colombier 		/* doesn't fit; just patch the count and return */
500*8ccd4a63SDavid du Colombier 		PBIT16((uchar*)dp, r->reply.nstat);
501*8ccd4a63SDavid du Colombier 		n = BIT16SZ;
502*8ccd4a63SDavid du Colombier 	}else{
503*8ccd4a63SDavid du Colombier 		n = r->reply.nstat;
504*8ccd4a63SDavid du Colombier 		memmove(dp, r->reply.stat, n);
505*8ccd4a63SDavid du Colombier 		validstat(dp, n);
506*8ccd4a63SDavid du Colombier 		mntdirfix(dp, c);
507*8ccd4a63SDavid du Colombier 	}
508*8ccd4a63SDavid du Colombier 	poperror();
509*8ccd4a63SDavid du Colombier 	mntfree(r);
510*8ccd4a63SDavid du Colombier 	return n;
511*8ccd4a63SDavid du Colombier }
512*8ccd4a63SDavid du Colombier 
513*8ccd4a63SDavid du Colombier static Chan*
514*8ccd4a63SDavid du Colombier mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
515*8ccd4a63SDavid du Colombier {
516*8ccd4a63SDavid du Colombier 	Mnt *m;
517*8ccd4a63SDavid du Colombier 	Mntrpc *r;
518*8ccd4a63SDavid du Colombier 
519*8ccd4a63SDavid du Colombier 	m = mntchk(c);
520*8ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
521*8ccd4a63SDavid du Colombier 	if(waserror()) {
522*8ccd4a63SDavid du Colombier 		mntfree(r);
523*8ccd4a63SDavid du Colombier 		nexterror();
524*8ccd4a63SDavid du Colombier 	}
525*8ccd4a63SDavid du Colombier 	r->request.type = type;
526*8ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
527*8ccd4a63SDavid du Colombier 	r->request.mode = omode;
528*8ccd4a63SDavid du Colombier 	if(type == Tcreate){
529*8ccd4a63SDavid du Colombier 		r->request.perm = perm;
530*8ccd4a63SDavid du Colombier 		r->request.name = name;
531*8ccd4a63SDavid du Colombier 	}
532*8ccd4a63SDavid du Colombier 	mountrpc(m, r);
533*8ccd4a63SDavid du Colombier 
534*8ccd4a63SDavid du Colombier 	c->qid = r->reply.qid;
535*8ccd4a63SDavid du Colombier 	c->offset = 0;
536*8ccd4a63SDavid du Colombier 	c->mode = openmode(omode);
537*8ccd4a63SDavid du Colombier 	c->iounit = r->reply.iounit;
538*8ccd4a63SDavid du Colombier 	if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
539*8ccd4a63SDavid du Colombier 		c->iounit = m->msize-IOHDRSZ;
540*8ccd4a63SDavid du Colombier 	c->flag |= COPEN;
541*8ccd4a63SDavid du Colombier 	poperror();
542*8ccd4a63SDavid du Colombier 	mntfree(r);
543*8ccd4a63SDavid du Colombier 
544*8ccd4a63SDavid du Colombier 	if(c->flag & CCACHE)
545*8ccd4a63SDavid du Colombier 		copen(c);
546*8ccd4a63SDavid du Colombier 
547*8ccd4a63SDavid du Colombier 	return c;
548*8ccd4a63SDavid du Colombier }
549*8ccd4a63SDavid du Colombier 
550*8ccd4a63SDavid du Colombier static Chan*
551*8ccd4a63SDavid du Colombier mntopen(Chan *c, int omode)
552*8ccd4a63SDavid du Colombier {
553*8ccd4a63SDavid du Colombier 	return mntopencreate(Topen, c, nil, omode, 0);
554*8ccd4a63SDavid du Colombier }
555*8ccd4a63SDavid du Colombier 
556*8ccd4a63SDavid du Colombier static void
557*8ccd4a63SDavid du Colombier mntcreate(Chan *c, char *name, int omode, ulong perm)
558*8ccd4a63SDavid du Colombier {
559*8ccd4a63SDavid du Colombier 	mntopencreate(Tcreate, c, name, omode, perm);
560*8ccd4a63SDavid du Colombier }
561*8ccd4a63SDavid du Colombier 
562*8ccd4a63SDavid du Colombier static void
563*8ccd4a63SDavid du Colombier mntclunk(Chan *c, int t)
564*8ccd4a63SDavid du Colombier {
565*8ccd4a63SDavid du Colombier 	Mnt *m;
566*8ccd4a63SDavid du Colombier 	Mntrpc *r;
567*8ccd4a63SDavid du Colombier 
568*8ccd4a63SDavid du Colombier 	m = mntchk(c);
569*8ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
570*8ccd4a63SDavid du Colombier 	if(waserror()){
571*8ccd4a63SDavid du Colombier 		mntfree(r);
572*8ccd4a63SDavid du Colombier 		nexterror();
573*8ccd4a63SDavid du Colombier 	}
574*8ccd4a63SDavid du Colombier 
575*8ccd4a63SDavid du Colombier 	r->request.type = t;
576*8ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
577*8ccd4a63SDavid du Colombier 	mountrpc(m, r);
578*8ccd4a63SDavid du Colombier 	mntfree(r);
579*8ccd4a63SDavid du Colombier 	poperror();
580*8ccd4a63SDavid du Colombier }
581*8ccd4a63SDavid du Colombier 
582*8ccd4a63SDavid du Colombier void
583*8ccd4a63SDavid du Colombier muxclose(Mnt *m)
584*8ccd4a63SDavid du Colombier {
585*8ccd4a63SDavid du Colombier 	Mntrpc *q, *r;
586*8ccd4a63SDavid du Colombier 
587*8ccd4a63SDavid du Colombier 	for(q = m->queue; q; q = r) {
588*8ccd4a63SDavid du Colombier 		r = q->list;
589*8ccd4a63SDavid du Colombier 		mntfree(q);
590*8ccd4a63SDavid du Colombier 	}
591*8ccd4a63SDavid du Colombier 	m->id = 0;
592*8ccd4a63SDavid du Colombier 	free(m->version);
593*8ccd4a63SDavid du Colombier 	m->version = nil;
594*8ccd4a63SDavid du Colombier 	mntpntfree(m);
595*8ccd4a63SDavid du Colombier }
596*8ccd4a63SDavid du Colombier 
597*8ccd4a63SDavid du Colombier void
598*8ccd4a63SDavid du Colombier mntpntfree(Mnt *m)
599*8ccd4a63SDavid du Colombier {
600*8ccd4a63SDavid du Colombier 	Mnt *f, **l;
601*8ccd4a63SDavid du Colombier 	Queue *q;
602*8ccd4a63SDavid du Colombier 
603*8ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
604*8ccd4a63SDavid du Colombier 	l = &mntalloc.list;
605*8ccd4a63SDavid du Colombier 	for(f = *l; f; f = f->list) {
606*8ccd4a63SDavid du Colombier 		if(f == m) {
607*8ccd4a63SDavid du Colombier 			*l = m->list;
608*8ccd4a63SDavid du Colombier 			break;
609*8ccd4a63SDavid du Colombier 		}
610*8ccd4a63SDavid du Colombier 		l = &f->list;
611*8ccd4a63SDavid du Colombier 	}
612*8ccd4a63SDavid du Colombier 	m->list = mntalloc.mntfree;
613*8ccd4a63SDavid du Colombier 	mntalloc.mntfree = m;
614*8ccd4a63SDavid du Colombier 	q = m->q;
615*8ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
616*8ccd4a63SDavid du Colombier 
617*8ccd4a63SDavid du Colombier 	qfree(q);
618*8ccd4a63SDavid du Colombier }
619*8ccd4a63SDavid du Colombier 
620*8ccd4a63SDavid du Colombier static void
621*8ccd4a63SDavid du Colombier mntclose(Chan *c)
622*8ccd4a63SDavid du Colombier {
623*8ccd4a63SDavid du Colombier 	mntclunk(c, Tclunk);
624*8ccd4a63SDavid du Colombier }
625*8ccd4a63SDavid du Colombier 
626*8ccd4a63SDavid du Colombier static void
627*8ccd4a63SDavid du Colombier mntremove(Chan *c)
628*8ccd4a63SDavid du Colombier {
629*8ccd4a63SDavid du Colombier 	mntclunk(c, Tremove);
630*8ccd4a63SDavid du Colombier }
631*8ccd4a63SDavid du Colombier 
632*8ccd4a63SDavid du Colombier static int
633*8ccd4a63SDavid du Colombier mntwstat(Chan *c, uchar *dp, int n)
634*8ccd4a63SDavid du Colombier {
635*8ccd4a63SDavid du Colombier 	Mnt *m;
636*8ccd4a63SDavid du Colombier 	Mntrpc *r;
637*8ccd4a63SDavid du Colombier 
638*8ccd4a63SDavid du Colombier 	m = mntchk(c);
639*8ccd4a63SDavid du Colombier 	r = mntralloc(c, m->msize);
640*8ccd4a63SDavid du Colombier 	if(waserror()) {
641*8ccd4a63SDavid du Colombier 		mntfree(r);
642*8ccd4a63SDavid du Colombier 		nexterror();
643*8ccd4a63SDavid du Colombier 	}
644*8ccd4a63SDavid du Colombier 	r->request.type = Twstat;
645*8ccd4a63SDavid du Colombier 	r->request.fid = c->fid;
646*8ccd4a63SDavid du Colombier 	r->request.nstat = n;
647*8ccd4a63SDavid du Colombier 	r->request.stat = dp;
648*8ccd4a63SDavid du Colombier 	mountrpc(m, r);
649*8ccd4a63SDavid du Colombier 	poperror();
650*8ccd4a63SDavid du Colombier 	mntfree(r);
651*8ccd4a63SDavid du Colombier 	return n;
652*8ccd4a63SDavid du Colombier }
653*8ccd4a63SDavid du Colombier 
654*8ccd4a63SDavid du Colombier static long
655*8ccd4a63SDavid du Colombier mntread(Chan *c, void *buf, long n, vlong off)
656*8ccd4a63SDavid du Colombier {
657*8ccd4a63SDavid du Colombier 	uchar *p, *e;
658*8ccd4a63SDavid du Colombier 	int nc, cache, isdir, dirlen;
659*8ccd4a63SDavid du Colombier 
660*8ccd4a63SDavid du Colombier 	isdir = 0;
661*8ccd4a63SDavid du Colombier 	cache = c->flag & CCACHE;
662*8ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR) {
663*8ccd4a63SDavid du Colombier 		cache = 0;
664*8ccd4a63SDavid du Colombier 		isdir = 1;
665*8ccd4a63SDavid du Colombier 	}
666*8ccd4a63SDavid du Colombier 
667*8ccd4a63SDavid du Colombier 	p = buf;
668*8ccd4a63SDavid du Colombier 	if(cache) {
669*8ccd4a63SDavid du Colombier 		nc = cread(c, buf, n, off);
670*8ccd4a63SDavid du Colombier 		if(nc > 0) {
671*8ccd4a63SDavid du Colombier 			n -= nc;
672*8ccd4a63SDavid du Colombier 			if(n == 0)
673*8ccd4a63SDavid du Colombier 				return nc;
674*8ccd4a63SDavid du Colombier 			p += nc;
675*8ccd4a63SDavid du Colombier 			off += nc;
676*8ccd4a63SDavid du Colombier 		}
677*8ccd4a63SDavid du Colombier 		n = mntrdwr(Tread, c, p, n, off);
678*8ccd4a63SDavid du Colombier 		cupdate(c, p, n, off);
679*8ccd4a63SDavid du Colombier 		return n + nc;
680*8ccd4a63SDavid du Colombier 	}
681*8ccd4a63SDavid du Colombier 
682*8ccd4a63SDavid du Colombier 	n = mntrdwr(Tread, c, buf, n, off);
683*8ccd4a63SDavid du Colombier 	if(isdir) {
684*8ccd4a63SDavid du Colombier 		for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
685*8ccd4a63SDavid du Colombier 			dirlen = BIT16SZ+GBIT16(p);
686*8ccd4a63SDavid du Colombier 			if(p+dirlen > e)
687*8ccd4a63SDavid du Colombier 				break;
688*8ccd4a63SDavid du Colombier 			validstat(p, dirlen);
689*8ccd4a63SDavid du Colombier 			mntdirfix(p, c);
690*8ccd4a63SDavid du Colombier 		}
691*8ccd4a63SDavid du Colombier 		if(p != e)
692*8ccd4a63SDavid du Colombier 			error(Esbadstat);
693*8ccd4a63SDavid du Colombier 	}
694*8ccd4a63SDavid du Colombier 	return n;
695*8ccd4a63SDavid du Colombier }
696*8ccd4a63SDavid du Colombier 
697*8ccd4a63SDavid du Colombier static long
698*8ccd4a63SDavid du Colombier mntwrite(Chan *c, void *buf, long n, vlong off)
699*8ccd4a63SDavid du Colombier {
700*8ccd4a63SDavid du Colombier 	return mntrdwr(Twrite, c, buf, n, off);
701*8ccd4a63SDavid du Colombier }
702*8ccd4a63SDavid du Colombier 
703*8ccd4a63SDavid du Colombier long
704*8ccd4a63SDavid du Colombier mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
705*8ccd4a63SDavid du Colombier {
706*8ccd4a63SDavid du Colombier 	Mnt *m;
707*8ccd4a63SDavid du Colombier  	Mntrpc *r;
708*8ccd4a63SDavid du Colombier 	char *uba;
709*8ccd4a63SDavid du Colombier 	int cache;
710*8ccd4a63SDavid du Colombier 	ulong cnt, nr, nreq;
711*8ccd4a63SDavid du Colombier 
712*8ccd4a63SDavid du Colombier 	m = mntchk(c);
713*8ccd4a63SDavid du Colombier 	uba = buf;
714*8ccd4a63SDavid du Colombier 	cnt = 0;
715*8ccd4a63SDavid du Colombier 	cache = c->flag & CCACHE;
716*8ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR)
717*8ccd4a63SDavid du Colombier 		cache = 0;
718*8ccd4a63SDavid du Colombier 	for(;;) {
719*8ccd4a63SDavid du Colombier 		r = mntralloc(c, m->msize);
720*8ccd4a63SDavid du Colombier 		if(waserror()) {
721*8ccd4a63SDavid du Colombier 			mntfree(r);
722*8ccd4a63SDavid du Colombier 			nexterror();
723*8ccd4a63SDavid du Colombier 		}
724*8ccd4a63SDavid du Colombier 		r->request.type = type;
725*8ccd4a63SDavid du Colombier 		r->request.fid = c->fid;
726*8ccd4a63SDavid du Colombier 		r->request.offset = off;
727*8ccd4a63SDavid du Colombier 		r->request.data = uba;
728*8ccd4a63SDavid du Colombier 		nr = n;
729*8ccd4a63SDavid du Colombier 		if(nr > m->msize-IOHDRSZ)
730*8ccd4a63SDavid du Colombier 			nr = m->msize-IOHDRSZ;
731*8ccd4a63SDavid du Colombier 		r->request.count = nr;
732*8ccd4a63SDavid du Colombier 		mountrpc(m, r);
733*8ccd4a63SDavid du Colombier 		nreq = r->request.count;
734*8ccd4a63SDavid du Colombier 		nr = r->reply.count;
735*8ccd4a63SDavid du Colombier 		if(nr > nreq)
736*8ccd4a63SDavid du Colombier 			nr = nreq;
737*8ccd4a63SDavid du Colombier 
738*8ccd4a63SDavid du Colombier 		if(type == Tread)
739*8ccd4a63SDavid du Colombier 			r->b = bl2mem((uchar*)uba, r->b, nr);
740*8ccd4a63SDavid du Colombier 		else if(cache)
741*8ccd4a63SDavid du Colombier 			cwrite(c, (uchar*)uba, nr, off);
742*8ccd4a63SDavid du Colombier 
743*8ccd4a63SDavid du Colombier 		poperror();
744*8ccd4a63SDavid du Colombier 		mntfree(r);
745*8ccd4a63SDavid du Colombier 		off += nr;
746*8ccd4a63SDavid du Colombier 		uba += nr;
747*8ccd4a63SDavid du Colombier 		cnt += nr;
748*8ccd4a63SDavid du Colombier 		n -= nr;
749*8ccd4a63SDavid du Colombier 		if(nr != nreq || n == 0)
750*8ccd4a63SDavid du Colombier 			break;
751*8ccd4a63SDavid du Colombier 	}
752*8ccd4a63SDavid du Colombier 	return cnt;
753*8ccd4a63SDavid du Colombier }
754*8ccd4a63SDavid du Colombier 
755*8ccd4a63SDavid du Colombier void
756*8ccd4a63SDavid du Colombier mountrpc(Mnt *m, Mntrpc *r)
757*8ccd4a63SDavid du Colombier {
758*8ccd4a63SDavid du Colombier 	char *sn, *cn;
759*8ccd4a63SDavid du Colombier 	int t;
760*8ccd4a63SDavid du Colombier 
761*8ccd4a63SDavid du Colombier 	r->reply.tag = 0;
762*8ccd4a63SDavid du Colombier 	r->reply.type = Tmax;	/* can't ever be a valid message type */
763*8ccd4a63SDavid du Colombier 
764*8ccd4a63SDavid du Colombier 	mountio(m, r);
765*8ccd4a63SDavid du Colombier 
766*8ccd4a63SDavid du Colombier 	t = r->reply.type;
767*8ccd4a63SDavid du Colombier 	switch(t) {
768*8ccd4a63SDavid du Colombier 	case Rerror:
769*8ccd4a63SDavid du Colombier 		error(r->reply.ename);
770*8ccd4a63SDavid du Colombier 	case Rflush:
771*8ccd4a63SDavid du Colombier 		error(Eintr);
772*8ccd4a63SDavid du Colombier 	default:
773*8ccd4a63SDavid du Colombier 		if(t == r->request.type+1)
774*8ccd4a63SDavid du Colombier 			break;
775*8ccd4a63SDavid du Colombier 		sn = "?";
776*8ccd4a63SDavid du Colombier 		if(m->c->name != nil)
777*8ccd4a63SDavid du Colombier 			sn = m->c->name->s;
778*8ccd4a63SDavid du Colombier 		cn = "?";
779*8ccd4a63SDavid du Colombier 		if(r->c != nil && r->c->name != nil)
780*8ccd4a63SDavid du Colombier 			cn = r->c->name->s;
781*8ccd4a63SDavid du Colombier 		print("mnt: proc %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n",
782*8ccd4a63SDavid du Colombier 			up->pid, sn, cn,
783*8ccd4a63SDavid du Colombier 			r, r->request.tag, r->request.fid, r->request.type,
784*8ccd4a63SDavid du Colombier 			r->reply.type, r->reply.tag);
785*8ccd4a63SDavid du Colombier 		error(Emountrpc);
786*8ccd4a63SDavid du Colombier 	}
787*8ccd4a63SDavid du Colombier }
788*8ccd4a63SDavid du Colombier 
789*8ccd4a63SDavid du Colombier void
790*8ccd4a63SDavid du Colombier mountio(Mnt *m, Mntrpc *r)
791*8ccd4a63SDavid du Colombier {
792*8ccd4a63SDavid du Colombier 	int n;
793*8ccd4a63SDavid du Colombier 
794*8ccd4a63SDavid du Colombier 	while(waserror()) {
795*8ccd4a63SDavid du Colombier 		if(m->rip == up)
796*8ccd4a63SDavid du Colombier 			mntgate(m);
797*8ccd4a63SDavid du Colombier 		if(strcmp(up->errstr, Eintr) != 0){
798*8ccd4a63SDavid du Colombier 			mntflushfree(m, r);
799*8ccd4a63SDavid du Colombier 			nexterror();
800*8ccd4a63SDavid du Colombier 		}
801*8ccd4a63SDavid du Colombier 		r = mntflushalloc(r, m->msize);
802*8ccd4a63SDavid du Colombier 	}
803*8ccd4a63SDavid du Colombier 
804*8ccd4a63SDavid du Colombier 	lock(&m->lk);
805*8ccd4a63SDavid du Colombier 	r->m = m;
806*8ccd4a63SDavid du Colombier 	r->list = m->queue;
807*8ccd4a63SDavid du Colombier 	m->queue = r;
808*8ccd4a63SDavid du Colombier 	unlock(&m->lk);
809*8ccd4a63SDavid du Colombier 
810*8ccd4a63SDavid du Colombier 	/* Transmit a file system rpc */
811*8ccd4a63SDavid du Colombier 	if(m->msize == 0)
812*8ccd4a63SDavid du Colombier 		panic("msize");
813*8ccd4a63SDavid du Colombier 	n = convS2M(&r->request, r->rpc, m->msize);
814*8ccd4a63SDavid du Colombier 	if(n < 0)
815*8ccd4a63SDavid du Colombier 		panic("bad message type in mountio");
816*8ccd4a63SDavid du Colombier 	if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
817*8ccd4a63SDavid du Colombier 		error(Emountrpc);
818*8ccd4a63SDavid du Colombier 	r->stime = fastticks(nil);
819*8ccd4a63SDavid du Colombier 	r->reqlen = n;
820*8ccd4a63SDavid du Colombier 
821*8ccd4a63SDavid du Colombier 	/* Gate readers onto the mount point one at a time */
822*8ccd4a63SDavid du Colombier 	for(;;) {
823*8ccd4a63SDavid du Colombier 		lock(&m->lk);
824*8ccd4a63SDavid du Colombier 		if(m->rip == 0)
825*8ccd4a63SDavid du Colombier 			break;
826*8ccd4a63SDavid du Colombier 		unlock(&m->lk);
827*8ccd4a63SDavid du Colombier 		sleep(&r->r, rpcattn, r);
828*8ccd4a63SDavid du Colombier 		if(r->done){
829*8ccd4a63SDavid du Colombier 			poperror();
830*8ccd4a63SDavid du Colombier 			mntflushfree(m, r);
831*8ccd4a63SDavid du Colombier 			return;
832*8ccd4a63SDavid du Colombier 		}
833*8ccd4a63SDavid du Colombier 	}
834*8ccd4a63SDavid du Colombier 	m->rip = up;
835*8ccd4a63SDavid du Colombier 	unlock(&m->lk);
836*8ccd4a63SDavid du Colombier 	while(r->done == 0) {
837*8ccd4a63SDavid du Colombier 		if(mntrpcread(m, r) < 0)
838*8ccd4a63SDavid du Colombier 			error(Emountrpc);
839*8ccd4a63SDavid du Colombier 		mountmux(m, r);
840*8ccd4a63SDavid du Colombier 	}
841*8ccd4a63SDavid du Colombier 	mntgate(m);
842*8ccd4a63SDavid du Colombier 	poperror();
843*8ccd4a63SDavid du Colombier 	mntflushfree(m, r);
844*8ccd4a63SDavid du Colombier }
845*8ccd4a63SDavid du Colombier 
846*8ccd4a63SDavid du Colombier static int
847*8ccd4a63SDavid du Colombier doread(Mnt *m, int len)
848*8ccd4a63SDavid du Colombier {
849*8ccd4a63SDavid du Colombier 	Block *b;
850*8ccd4a63SDavid du Colombier 
851*8ccd4a63SDavid du Colombier 	while(qlen(m->q) < len){
852*8ccd4a63SDavid du Colombier 		b = devtab[m->c->type]->bread(m->c, m->msize, 0);
853*8ccd4a63SDavid du Colombier 		if(b == nil)
854*8ccd4a63SDavid du Colombier 			return -1;
855*8ccd4a63SDavid du Colombier 		if(BLEN(b) == 0){
856*8ccd4a63SDavid du Colombier 			freeblist(b);
857*8ccd4a63SDavid du Colombier 			return -1;
858*8ccd4a63SDavid du Colombier 		}
859*8ccd4a63SDavid du Colombier 		qaddlist(m->q, b);
860*8ccd4a63SDavid du Colombier 	}
861*8ccd4a63SDavid du Colombier 	return 0;
862*8ccd4a63SDavid du Colombier }
863*8ccd4a63SDavid du Colombier 
864*8ccd4a63SDavid du Colombier int
865*8ccd4a63SDavid du Colombier mntrpcread(Mnt *m, Mntrpc *r)
866*8ccd4a63SDavid du Colombier {
867*8ccd4a63SDavid du Colombier 	int i, t, len, hlen;
868*8ccd4a63SDavid du Colombier 	Block *b, **l, *nb;
869*8ccd4a63SDavid du Colombier 
870*8ccd4a63SDavid du Colombier 	r->reply.type = 0;
871*8ccd4a63SDavid du Colombier 	r->reply.tag = 0;
872*8ccd4a63SDavid du Colombier 
873*8ccd4a63SDavid du Colombier 	/* read at least length, type, and tag and pullup to a single block */
874*8ccd4a63SDavid du Colombier 	if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
875*8ccd4a63SDavid du Colombier 		return -1;
876*8ccd4a63SDavid du Colombier 	nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
877*8ccd4a63SDavid du Colombier 
878*8ccd4a63SDavid du Colombier 	/* read in the rest of the message, avoid rediculous (for now) message sizes */
879*8ccd4a63SDavid du Colombier 	len = GBIT32(nb->rp);
880*8ccd4a63SDavid du Colombier 	if(len > m->msize){
881*8ccd4a63SDavid du Colombier 		qdiscard(m->q, qlen(m->q));
882*8ccd4a63SDavid du Colombier 		return -1;
883*8ccd4a63SDavid du Colombier 	}
884*8ccd4a63SDavid du Colombier 	if(doread(m, len) < 0)
885*8ccd4a63SDavid du Colombier 		return -1;
886*8ccd4a63SDavid du Colombier 
887*8ccd4a63SDavid du Colombier 	/* pullup the header (i.e. everything except data) */
888*8ccd4a63SDavid du Colombier 	t = nb->rp[BIT32SZ];
889*8ccd4a63SDavid du Colombier 	switch(t){
890*8ccd4a63SDavid du Colombier 	case Rread:
891*8ccd4a63SDavid du Colombier 		hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
892*8ccd4a63SDavid du Colombier 		break;
893*8ccd4a63SDavid du Colombier 	default:
894*8ccd4a63SDavid du Colombier 		hlen = len;
895*8ccd4a63SDavid du Colombier 		break;
896*8ccd4a63SDavid du Colombier 	}
897*8ccd4a63SDavid du Colombier 	nb = pullupqueue(m->q, hlen);
898*8ccd4a63SDavid du Colombier 
899*8ccd4a63SDavid du Colombier 	if(convM2S(nb->rp, len, &r->reply) <= 0){
900*8ccd4a63SDavid du Colombier 		/* bad message, dump it */
901*8ccd4a63SDavid du Colombier 		print("mntrpcread: convM2S failed\n");
902*8ccd4a63SDavid du Colombier 		qdiscard(m->q, len);
903*8ccd4a63SDavid du Colombier 		return -1;
904*8ccd4a63SDavid du Colombier 	}
905*8ccd4a63SDavid du Colombier 
906*8ccd4a63SDavid du Colombier 	/* hang the data off of the fcall struct */
907*8ccd4a63SDavid du Colombier 	l = &r->b;
908*8ccd4a63SDavid du Colombier 	*l = nil;
909*8ccd4a63SDavid du Colombier 	do {
910*8ccd4a63SDavid du Colombier 		b = qremove(m->q);
911*8ccd4a63SDavid du Colombier 		if(hlen > 0){
912*8ccd4a63SDavid du Colombier 			b->rp += hlen;
913*8ccd4a63SDavid du Colombier 			len -= hlen;
914*8ccd4a63SDavid du Colombier 			hlen = 0;
915*8ccd4a63SDavid du Colombier 		}
916*8ccd4a63SDavid du Colombier 		i = BLEN(b);
917*8ccd4a63SDavid du Colombier 		if(i <= len){
918*8ccd4a63SDavid du Colombier 			len -= i;
919*8ccd4a63SDavid du Colombier 			*l = b;
920*8ccd4a63SDavid du Colombier 			l = &(b->next);
921*8ccd4a63SDavid du Colombier 		} else {
922*8ccd4a63SDavid du Colombier 			/* split block and put unused bit back */
923*8ccd4a63SDavid du Colombier 			nb = allocb(i-len);
924*8ccd4a63SDavid du Colombier 			memmove(nb->wp, b->rp+len, i-len);
925*8ccd4a63SDavid du Colombier 			b->wp = b->rp+len;
926*8ccd4a63SDavid du Colombier 			nb->wp += i-len;
927*8ccd4a63SDavid du Colombier 			qputback(m->q, nb);
928*8ccd4a63SDavid du Colombier 			*l = b;
929*8ccd4a63SDavid du Colombier 			return 0;
930*8ccd4a63SDavid du Colombier 		}
931*8ccd4a63SDavid du Colombier 	}while(len > 0);
932*8ccd4a63SDavid du Colombier 
933*8ccd4a63SDavid du Colombier 	return 0;
934*8ccd4a63SDavid du Colombier }
935*8ccd4a63SDavid du Colombier 
936*8ccd4a63SDavid du Colombier void
937*8ccd4a63SDavid du Colombier mntgate(Mnt *m)
938*8ccd4a63SDavid du Colombier {
939*8ccd4a63SDavid du Colombier 	Mntrpc *q;
940*8ccd4a63SDavid du Colombier 
941*8ccd4a63SDavid du Colombier 	lock(&m->lk);
942*8ccd4a63SDavid du Colombier 	m->rip = 0;
943*8ccd4a63SDavid du Colombier 	for(q = m->queue; q; q = q->list) {
944*8ccd4a63SDavid du Colombier 		if(q->done == 0)
945*8ccd4a63SDavid du Colombier 		if(wakeup(&q->r))
946*8ccd4a63SDavid du Colombier 			break;
947*8ccd4a63SDavid du Colombier 	}
948*8ccd4a63SDavid du Colombier 	unlock(&m->lk);
949*8ccd4a63SDavid du Colombier }
950*8ccd4a63SDavid du Colombier 
951*8ccd4a63SDavid du Colombier void
952*8ccd4a63SDavid du Colombier mountmux(Mnt *m, Mntrpc *r)
953*8ccd4a63SDavid du Colombier {
954*8ccd4a63SDavid du Colombier 	Mntrpc **l, *q;
955*8ccd4a63SDavid du Colombier 
956*8ccd4a63SDavid du Colombier 	lock(&m->lk);
957*8ccd4a63SDavid du Colombier 	l = &m->queue;
958*8ccd4a63SDavid du Colombier 	for(q = *l; q; q = q->list) {
959*8ccd4a63SDavid du Colombier 		/* look for a reply to a message */
960*8ccd4a63SDavid du Colombier 		if(q->request.tag == r->reply.tag) {
961*8ccd4a63SDavid du Colombier 			*l = q->list;
962*8ccd4a63SDavid du Colombier 			if(q != r) {
963*8ccd4a63SDavid du Colombier 				/*
964*8ccd4a63SDavid du Colombier 				 * Completed someone else.
965*8ccd4a63SDavid du Colombier 				 * Trade pointers to receive buffer.
966*8ccd4a63SDavid du Colombier 				 */
967*8ccd4a63SDavid du Colombier 				q->reply = r->reply;
968*8ccd4a63SDavid du Colombier 				q->b = r->b;
969*8ccd4a63SDavid du Colombier 				r->b = nil;
970*8ccd4a63SDavid du Colombier 			}
971*8ccd4a63SDavid du Colombier 			q->done = 1;
972*8ccd4a63SDavid du Colombier 			unlock(&m->lk);
973*8ccd4a63SDavid du Colombier 			if(mntstats != nil)
974*8ccd4a63SDavid du Colombier 				(*mntstats)(q->request.type,
975*8ccd4a63SDavid du Colombier 					m->c, q->stime,
976*8ccd4a63SDavid du Colombier 					q->reqlen + r->replen);
977*8ccd4a63SDavid du Colombier 			if(q != r)
978*8ccd4a63SDavid du Colombier 				wakeup(&q->r);
979*8ccd4a63SDavid du Colombier 			return;
980*8ccd4a63SDavid du Colombier 		}
981*8ccd4a63SDavid du Colombier 		l = &q->list;
982*8ccd4a63SDavid du Colombier 	}
983*8ccd4a63SDavid du Colombier 	unlock(&m->lk);
984*8ccd4a63SDavid du Colombier 	print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
985*8ccd4a63SDavid du Colombier }
986*8ccd4a63SDavid du Colombier 
987*8ccd4a63SDavid du Colombier /*
988*8ccd4a63SDavid du Colombier  * Create a new flush request and chain the previous
989*8ccd4a63SDavid du Colombier  * requests from it
990*8ccd4a63SDavid du Colombier  */
991*8ccd4a63SDavid du Colombier Mntrpc*
992*8ccd4a63SDavid du Colombier mntflushalloc(Mntrpc *r, ulong iounit)
993*8ccd4a63SDavid du Colombier {
994*8ccd4a63SDavid du Colombier 	Mntrpc *fr;
995*8ccd4a63SDavid du Colombier 
996*8ccd4a63SDavid du Colombier 	fr = mntralloc(0, iounit);
997*8ccd4a63SDavid du Colombier 
998*8ccd4a63SDavid du Colombier 	fr->request.type = Tflush;
999*8ccd4a63SDavid du Colombier 	if(r->request.type == Tflush)
1000*8ccd4a63SDavid du Colombier 		fr->request.oldtag = r->request.oldtag;
1001*8ccd4a63SDavid du Colombier 	else
1002*8ccd4a63SDavid du Colombier 		fr->request.oldtag = r->request.tag;
1003*8ccd4a63SDavid du Colombier 	fr->flushed = r;
1004*8ccd4a63SDavid du Colombier 
1005*8ccd4a63SDavid du Colombier 	return fr;
1006*8ccd4a63SDavid du Colombier }
1007*8ccd4a63SDavid du Colombier 
1008*8ccd4a63SDavid du Colombier /*
1009*8ccd4a63SDavid du Colombier  *  Free a chain of flushes.  Remove each unanswered
1010*8ccd4a63SDavid du Colombier  *  flush and the original message from the unanswered
1011*8ccd4a63SDavid du Colombier  *  request queue.  Mark the original message as done
1012*8ccd4a63SDavid du Colombier  *  and if it hasn't been answered set the reply to to
1013*8ccd4a63SDavid du Colombier  *  Rflush.
1014*8ccd4a63SDavid du Colombier  */
1015*8ccd4a63SDavid du Colombier void
1016*8ccd4a63SDavid du Colombier mntflushfree(Mnt *m, Mntrpc *r)
1017*8ccd4a63SDavid du Colombier {
1018*8ccd4a63SDavid du Colombier 	Mntrpc *fr;
1019*8ccd4a63SDavid du Colombier 
1020*8ccd4a63SDavid du Colombier 	while(r){
1021*8ccd4a63SDavid du Colombier 		fr = r->flushed;
1022*8ccd4a63SDavid du Colombier 		if(!r->done){
1023*8ccd4a63SDavid du Colombier 			r->reply.type = Rflush;
1024*8ccd4a63SDavid du Colombier 			mntqrm(m, r);
1025*8ccd4a63SDavid du Colombier 		}
1026*8ccd4a63SDavid du Colombier 		if(fr)
1027*8ccd4a63SDavid du Colombier 			mntfree(r);
1028*8ccd4a63SDavid du Colombier 		r = fr;
1029*8ccd4a63SDavid du Colombier 	}
1030*8ccd4a63SDavid du Colombier }
1031*8ccd4a63SDavid du Colombier 
1032*8ccd4a63SDavid du Colombier int
1033*8ccd4a63SDavid du Colombier alloctag(void)
1034*8ccd4a63SDavid du Colombier {
1035*8ccd4a63SDavid du Colombier 	int i, j;
1036*8ccd4a63SDavid du Colombier 	ulong v;
1037*8ccd4a63SDavid du Colombier 
1038*8ccd4a63SDavid du Colombier 	for(i = 0; i < NMASK; i++){
1039*8ccd4a63SDavid du Colombier 		v = mntalloc.tagmask[i];
1040*8ccd4a63SDavid du Colombier 		if(v == ~0UL)
1041*8ccd4a63SDavid du Colombier 			continue;
1042*8ccd4a63SDavid du Colombier 		for(j = 0; j < 1<<TAGSHIFT; j++)
1043*8ccd4a63SDavid du Colombier 			if((v & (1<<j)) == 0){
1044*8ccd4a63SDavid du Colombier 				mntalloc.tagmask[i] |= 1<<j;
1045*8ccd4a63SDavid du Colombier 				return (i<<TAGSHIFT) + j;
1046*8ccd4a63SDavid du Colombier 			}
1047*8ccd4a63SDavid du Colombier 	}
1048*8ccd4a63SDavid du Colombier 	panic("no friggin tags left");
1049*8ccd4a63SDavid du Colombier 	return NOTAG;
1050*8ccd4a63SDavid du Colombier }
1051*8ccd4a63SDavid du Colombier 
1052*8ccd4a63SDavid du Colombier void
1053*8ccd4a63SDavid du Colombier freetag(int t)
1054*8ccd4a63SDavid du Colombier {
1055*8ccd4a63SDavid du Colombier 	mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1056*8ccd4a63SDavid du Colombier }
1057*8ccd4a63SDavid du Colombier 
1058*8ccd4a63SDavid du Colombier Mntrpc*
1059*8ccd4a63SDavid du Colombier mntralloc(Chan *c, ulong msize)
1060*8ccd4a63SDavid du Colombier {
1061*8ccd4a63SDavid du Colombier 	Mntrpc *new;
1062*8ccd4a63SDavid du Colombier 
1063*8ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
1064*8ccd4a63SDavid du Colombier 	new = mntalloc.rpcfree;
1065*8ccd4a63SDavid du Colombier 	if(new == nil){
1066*8ccd4a63SDavid du Colombier 		new = malloc(sizeof(Mntrpc));
1067*8ccd4a63SDavid du Colombier 		if(new == nil) {
1068*8ccd4a63SDavid du Colombier 			unlock(&mntalloc.lk);
1069*8ccd4a63SDavid du Colombier 			exhausted("mount rpc header");
1070*8ccd4a63SDavid du Colombier 		}
1071*8ccd4a63SDavid du Colombier 		/*
1072*8ccd4a63SDavid du Colombier 		 * The header is split from the data buffer as
1073*8ccd4a63SDavid du Colombier 		 * mountmux may swap the buffer with another header.
1074*8ccd4a63SDavid du Colombier 		 */
1075*8ccd4a63SDavid du Colombier 		new->rpc = mallocz(msize, 0);
1076*8ccd4a63SDavid du Colombier 		if(new->rpc == nil){
1077*8ccd4a63SDavid du Colombier 			free(new);
1078*8ccd4a63SDavid du Colombier 			unlock(&mntalloc.lk);
1079*8ccd4a63SDavid du Colombier 			exhausted("mount rpc buffer");
1080*8ccd4a63SDavid du Colombier 		}
1081*8ccd4a63SDavid du Colombier 		new->rpclen = msize;
1082*8ccd4a63SDavid du Colombier 		new->request.tag = alloctag();
1083*8ccd4a63SDavid du Colombier 	}
1084*8ccd4a63SDavid du Colombier 	else {
1085*8ccd4a63SDavid du Colombier 		mntalloc.rpcfree = new->list;
1086*8ccd4a63SDavid du Colombier 		mntalloc.nrpcfree--;
1087*8ccd4a63SDavid du Colombier 		if(new->rpclen < msize){
1088*8ccd4a63SDavid du Colombier 			free(new->rpc);
1089*8ccd4a63SDavid du Colombier 			new->rpc = mallocz(msize, 0);
1090*8ccd4a63SDavid du Colombier 			if(new->rpc == nil){
1091*8ccd4a63SDavid du Colombier 				free(new);
1092*8ccd4a63SDavid du Colombier 				mntalloc.nrpcused--;
1093*8ccd4a63SDavid du Colombier 				unlock(&mntalloc.lk);
1094*8ccd4a63SDavid du Colombier 				exhausted("mount rpc buffer");
1095*8ccd4a63SDavid du Colombier 			}
1096*8ccd4a63SDavid du Colombier 			new->rpclen = msize;
1097*8ccd4a63SDavid du Colombier 		}
1098*8ccd4a63SDavid du Colombier 	}
1099*8ccd4a63SDavid du Colombier 	mntalloc.nrpcused++;
1100*8ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
1101*8ccd4a63SDavid du Colombier 	new->c = c;
1102*8ccd4a63SDavid du Colombier 	new->done = 0;
1103*8ccd4a63SDavid du Colombier 	new->flushed = nil;
1104*8ccd4a63SDavid du Colombier 	new->b = nil;
1105*8ccd4a63SDavid du Colombier 	return new;
1106*8ccd4a63SDavid du Colombier }
1107*8ccd4a63SDavid du Colombier 
1108*8ccd4a63SDavid du Colombier void
1109*8ccd4a63SDavid du Colombier mntfree(Mntrpc *r)
1110*8ccd4a63SDavid du Colombier {
1111*8ccd4a63SDavid du Colombier 	if(r->b != nil)
1112*8ccd4a63SDavid du Colombier 		freeblist(r->b);
1113*8ccd4a63SDavid du Colombier 	lock(&mntalloc.lk);
1114*8ccd4a63SDavid du Colombier 	if(mntalloc.nrpcfree >= 10){
1115*8ccd4a63SDavid du Colombier 		free(r->rpc);
1116*8ccd4a63SDavid du Colombier 		free(r);
1117*8ccd4a63SDavid du Colombier 		freetag(r->request.tag);
1118*8ccd4a63SDavid du Colombier 	}
1119*8ccd4a63SDavid du Colombier 	else{
1120*8ccd4a63SDavid du Colombier 		r->list = mntalloc.rpcfree;
1121*8ccd4a63SDavid du Colombier 		mntalloc.rpcfree = r;
1122*8ccd4a63SDavid du Colombier 		mntalloc.nrpcfree++;
1123*8ccd4a63SDavid du Colombier 	}
1124*8ccd4a63SDavid du Colombier 	mntalloc.nrpcused--;
1125*8ccd4a63SDavid du Colombier 	unlock(&mntalloc.lk);
1126*8ccd4a63SDavid du Colombier }
1127*8ccd4a63SDavid du Colombier 
1128*8ccd4a63SDavid du Colombier void
1129*8ccd4a63SDavid du Colombier mntqrm(Mnt *m, Mntrpc *r)
1130*8ccd4a63SDavid du Colombier {
1131*8ccd4a63SDavid du Colombier 	Mntrpc **l, *f;
1132*8ccd4a63SDavid du Colombier 
1133*8ccd4a63SDavid du Colombier 	lock(&m->lk);
1134*8ccd4a63SDavid du Colombier 	r->done = 1;
1135*8ccd4a63SDavid du Colombier 
1136*8ccd4a63SDavid du Colombier 	l = &m->queue;
1137*8ccd4a63SDavid du Colombier 	for(f = *l; f; f = f->list) {
1138*8ccd4a63SDavid du Colombier 		if(f == r) {
1139*8ccd4a63SDavid du Colombier 			*l = r->list;
1140*8ccd4a63SDavid du Colombier 			break;
1141*8ccd4a63SDavid du Colombier 		}
1142*8ccd4a63SDavid du Colombier 		l = &f->list;
1143*8ccd4a63SDavid du Colombier 	}
1144*8ccd4a63SDavid du Colombier 	unlock(&m->lk);
1145*8ccd4a63SDavid du Colombier }
1146*8ccd4a63SDavid du Colombier 
1147*8ccd4a63SDavid du Colombier Mnt*
1148*8ccd4a63SDavid du Colombier mntchk(Chan *c)
1149*8ccd4a63SDavid du Colombier {
1150*8ccd4a63SDavid du Colombier 	Mnt *m;
1151*8ccd4a63SDavid du Colombier 
1152*8ccd4a63SDavid du Colombier 	/* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1153*8ccd4a63SDavid du Colombier 
1154*8ccd4a63SDavid du Colombier 	if(c->mchan == nil)
1155*8ccd4a63SDavid du Colombier 		panic("mntchk 1: nil mchan c %s\n", c2name(c));
1156*8ccd4a63SDavid du Colombier 
1157*8ccd4a63SDavid du Colombier 	m = c->mchan->mux;
1158*8ccd4a63SDavid du Colombier 
1159*8ccd4a63SDavid du Colombier 	if(m == nil)
1160*8ccd4a63SDavid du Colombier 		print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan));
1161*8ccd4a63SDavid du Colombier 
1162*8ccd4a63SDavid du Colombier 	/*
1163*8ccd4a63SDavid du Colombier 	 * Was it closed and reused (was error(Eshutdown); now, it can't happen)
1164*8ccd4a63SDavid du Colombier 	 */
1165*8ccd4a63SDavid du Colombier 	if(m->id == 0 || m->id >= c->dev)
1166*8ccd4a63SDavid du Colombier 		panic("mntchk 3: can't happen");
1167*8ccd4a63SDavid du Colombier 
1168*8ccd4a63SDavid du Colombier 	return m;
1169*8ccd4a63SDavid du Colombier }
1170*8ccd4a63SDavid du Colombier 
1171*8ccd4a63SDavid du Colombier /*
1172*8ccd4a63SDavid du Colombier  * Rewrite channel type and dev for in-flight data to
1173*8ccd4a63SDavid du Colombier  * reflect local values.  These entries are known to be
1174*8ccd4a63SDavid du Colombier  * the first two in the Dir encoding after the count.
1175*8ccd4a63SDavid du Colombier  */
1176*8ccd4a63SDavid du Colombier void
1177*8ccd4a63SDavid du Colombier mntdirfix(uchar *dirbuf, Chan *c)
1178*8ccd4a63SDavid du Colombier {
1179*8ccd4a63SDavid du Colombier 	uint r;
1180*8ccd4a63SDavid du Colombier 
1181*8ccd4a63SDavid du Colombier 	r = devtab[c->type]->dc;
1182*8ccd4a63SDavid du Colombier 	dirbuf += BIT16SZ;	/* skip count */
1183*8ccd4a63SDavid du Colombier 	PBIT16(dirbuf, r);
1184*8ccd4a63SDavid du Colombier 	dirbuf += BIT16SZ;
1185*8ccd4a63SDavid du Colombier 	PBIT32(dirbuf, c->dev);
1186*8ccd4a63SDavid du Colombier }
1187*8ccd4a63SDavid du Colombier 
1188*8ccd4a63SDavid du Colombier int
1189*8ccd4a63SDavid du Colombier rpcattn(void *v)
1190*8ccd4a63SDavid du Colombier {
1191*8ccd4a63SDavid du Colombier 	Mntrpc *r;
1192*8ccd4a63SDavid du Colombier 
1193*8ccd4a63SDavid du Colombier 	r = v;
1194*8ccd4a63SDavid du Colombier 	return r->done || r->m->rip == 0;
1195*8ccd4a63SDavid du Colombier }
1196*8ccd4a63SDavid du Colombier 
1197*8ccd4a63SDavid du Colombier Dev mntdevtab = {
1198*8ccd4a63SDavid du Colombier 	'M',
1199*8ccd4a63SDavid du Colombier 	"mnt",
1200*8ccd4a63SDavid du Colombier 
1201*8ccd4a63SDavid du Colombier 	mntreset,
1202*8ccd4a63SDavid du Colombier 	devinit,
1203*8ccd4a63SDavid du Colombier 	devshutdown,
1204*8ccd4a63SDavid du Colombier 	mntattach,
1205*8ccd4a63SDavid du Colombier 	mntwalk,
1206*8ccd4a63SDavid du Colombier 	mntstat,
1207*8ccd4a63SDavid du Colombier 	mntopen,
1208*8ccd4a63SDavid du Colombier 	mntcreate,
1209*8ccd4a63SDavid du Colombier 	mntclose,
1210*8ccd4a63SDavid du Colombier 	mntread,
1211*8ccd4a63SDavid du Colombier 	devbread,
1212*8ccd4a63SDavid du Colombier 	mntwrite,
1213*8ccd4a63SDavid du Colombier 	devbwrite,
1214*8ccd4a63SDavid du Colombier 	mntremove,
1215*8ccd4a63SDavid du Colombier 	mntwstat,
1216*8ccd4a63SDavid du Colombier };
1217