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