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