Add the no op cache.c for devmnt.
[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(4);
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 - 1) * sizeof(struct qid), 0);
408         if(waserror()){
409                 if(alloc && wq->clone!=NULL)
410                         cclose(wq->clone);
411                 kfree(wq);
412                 return NULL;
413         }
414
415         alloc = 0;
416         m = mntchk(c);
417         r = mntralloc(c, m->msize);
418         if(nc == NULL){
419                 nc = devclone(c);
420                 /*
421                  * Until the other side accepts this fid, we can't mntclose it.
422                  * Therefore set type to 0 for now; rootclose is known to be safe.
423                  */
424                 nc->type = 0;
425                 alloc = 1;
426         }
427         wq->clone = nc;
428
429         if(waserror()) {
430                 mntfree(r);
431                 nexterror();
432         }
433         r->request.type = Twalk;
434         r->request.fid = c->fid;
435         r->request.newfid = nc->fid;
436         r->request.nwname = nname;
437         memmove(r->request.wname, name, nname*sizeof( char *));
438
439         mountrpc(m, r);
440
441         if(r->reply.nwqid > nname)
442                 error("too many QIDs returned by walk");
443         if(r->reply.nwqid < nname){
444                 if(alloc)
445                         cclose(nc);
446                 wq->clone = NULL;
447                 if(r->reply.nwqid == 0){
448                         kfree(wq);
449                         wq = NULL;
450                         goto Return;
451                 }
452         }
453
454         /* move new fid onto mnt device and update its qid */
455         if(wq->clone != NULL){
456                 if(wq->clone != c){
457                         wq->clone->type = c->type;
458                         wq->clone->mchan = c->mchan;
459                         incref(&c->mchan->ref);
460                 }
461                 if(r->reply.nwqid > 0)
462                         wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
463         }
464         wq->nqid = r->reply.nwqid;
465         for(i=0; i<wq->nqid; i++)
466                 wq->qid[i] = r->reply.wqid[i];
467
468     Return:
469         poperror();
470         mntfree(r);
471         poperror();
472         return wq;
473 }
474
475 static int
476 mntstat(struct chan *c, uint8_t *dp, int n)
477 {
478         ERRSTACK(2);
479         struct mnt *m;
480         struct mntrpc *r;
481
482         if(n < BIT16SZ)
483                 error(Eshortstat);
484         m = mntchk(c);
485         r = mntralloc(c, m->msize);
486         if(waserror()) {
487                 mntfree(r);
488                 nexterror();
489         }
490         r->request.type = Tstat;
491         r->request.fid = c->fid;
492         mountrpc(m, r);
493
494         if(r->reply.nstat > n){
495                 /* doesn't fit; just patch the count and return */
496                 PBIT16(( uint8_t *)dp, r->reply.nstat);
497                 n = BIT16SZ;
498         }else{
499                 n = r->reply.nstat;
500                 memmove(dp, r->reply.stat, n);
501                 validstat(dp, n);
502                 mntdirfix(dp, c);
503         }
504         poperror();
505         mntfree(r);
506         return n;
507 }
508
509 static struct chan*
510 mntopencreate(int type, struct chan *c, char *name, int omode, uint32_t perm)
511 {
512         ERRSTACK(2);
513         struct mnt *m;
514         struct mntrpc *r;
515
516         m = mntchk(c);
517         r = mntralloc(c, m->msize);
518         if(waserror()) {
519                 mntfree(r);
520                 nexterror();
521         }
522         r->request.type = type;
523         r->request.fid = c->fid;
524         r->request.mode = omode;
525         if(type == Tcreate){
526                 r->request.perm = perm;
527                 r->request.name = name;
528         }
529         mountrpc(m, r);
530
531         c->qid = r->reply.qid;
532         c->offset = 0;
533         c->mode = openmode(omode);
534         c->iounit = r->reply.iounit;
535         if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
536                 c->iounit = m->msize-IOHDRSZ;
537         c->flag |= COPEN;
538         poperror();
539         mntfree(r);
540
541         if(c->flag & CCACHE)
542                 copen(c);
543
544         return c;
545 }
546
547 static struct chan*
548 mntopen(struct chan *c, int omode)
549 {
550         return mntopencreate(Topen, c, NULL, omode, 0);
551 }
552
553 static void
554 mntcreate(struct chan *c, char *name, int omode, uint32_t perm)
555 {
556         mntopencreate(Tcreate, c, name, omode, perm);
557 }
558
559 static void
560 mntclunk(struct chan *c, int t)
561 {
562         ERRSTACK(2);
563         struct mnt *m;
564         struct mntrpc *r;
565
566         m = mntchk(c);
567         r = mntralloc(c, m->msize);
568         if(waserror()){
569                 mntfree(r);
570                 nexterror();
571         }
572
573         r->request.type = t;
574         r->request.fid = c->fid;
575         mountrpc(m, r);
576         mntfree(r);
577         poperror();
578 }
579
580 void
581 muxclose(struct mnt *m)
582 {
583         struct mntrpc *q, *r;
584
585         for(q = m->queue; q; q = r) {
586                 r = q->list;
587                 mntfree(q);
588         }
589         m->id = 0;
590         kfree(m->version);
591         m->version = NULL;
592         mntpntfree(m);
593 }
594
595 void
596 mntpntfree(struct mnt *m)
597 {
598         struct mnt *f, **l;
599         struct queue *q;
600
601         spin_lock(&mntalloc.l);
602         l = &mntalloc.list;
603         for(f = *l; f; f = f->list) {
604                 if(f == m) {
605                         *l = m->list;
606                         break;
607                 }
608                 l = &f->list;
609         }
610         m->list = mntalloc.mntfree;
611         mntalloc.mntfree = m;
612         q = m->q;
613         spin_unlock(&mntalloc.l);
614
615         qfree(q);
616 }
617
618 static void
619 mntclose(struct chan *c)
620 {
621         mntclunk(c, Tclunk);
622 }
623
624 static void
625 mntremove(struct chan *c)
626 {
627         mntclunk(c, Tremove);
628 }
629
630 static int
631 mntwstat(struct chan *c, uint8_t *dp, int n)
632 {
633         ERRSTACK(2);
634         struct mnt *m;
635         struct mntrpc *r;
636
637         m = mntchk(c);
638         r = mntralloc(c, m->msize);
639         if(waserror()) {
640                 mntfree(r);
641                 nexterror();
642         }
643         r->request.type = Twstat;
644         r->request.fid = c->fid;
645         r->request.nstat = n;
646         r->request.stat = dp;
647         mountrpc(m, r);
648         poperror();
649         mntfree(r);
650         return n;
651 }
652
653 static long
654 mntread(struct chan *c, void *buf, long n, int64_t off)
655 {
656         uint8_t *p, *e;
657         int nc, cache, isdir, dirlen;
658
659         isdir = 0;
660         cache = c->flag & CCACHE;
661         if(c->qid.type & QTDIR) {
662                 cache = 0;
663                 isdir = 1;
664         }
665
666         p = buf;
667         if(cache) {
668                 nc = cread(c, buf, n, off);
669                 if(nc > 0) {
670                         n -= nc;
671                         if(n == 0)
672                                 return nc;
673                         p += nc;
674                         off += nc;
675                 }
676                 n = mntrdwr(Tread, c, p, n, off);
677                 cupdate(c, p, n, off);
678                 return n + nc;
679         }
680
681         n = mntrdwr(Tread, c, buf, n, off);
682         if(isdir) {
683                 for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
684                         dirlen = BIT16SZ+GBIT16(p);
685                         if(p+dirlen > e)
686                                 break;
687                         validstat(p, dirlen);
688                         mntdirfix(p, c);
689                 }
690                 if(p != e)
691                         error(Esbadstat);
692         }
693         return n;
694 }
695
696 static long
697 mntwrite(struct chan *c, void *buf, long n, int64_t off)
698 {
699         return mntrdwr(Twrite, c, buf, n, off);
700 }
701
702 long
703 mntrdwr(int type, struct chan *c, void *buf, long n, int64_t off)
704 {
705         ERRSTACK(2);
706         struct mnt *m;
707         struct mntrpc *r;       /* TO DO: volatile struct { Mntrpc *r; } r; */
708         char *uba;
709         int cache;
710         uint32_t cnt, nr, nreq;
711
712         m = mntchk(c);
713         uba = buf;
714         cnt = 0;
715         cache = c->flag & CCACHE;
716         if(c->qid.type & QTDIR)
717                 cache = 0;
718         for(;;) {
719                 r = mntralloc(c, m->msize);
720                 if(waserror()) {
721                         mntfree(r);
722                         nexterror();
723                 }
724                 r->request.type = type;
725                 r->request.fid = c->fid;
726                 r->request.offset = off;
727                 r->request.data = uba;
728                 nr = n;
729                 if(nr > m->msize-IOHDRSZ)
730                         nr = m->msize-IOHDRSZ;
731                 r->request.count = nr;
732                 mountrpc(m, r);
733                 nreq = r->request.count;
734                 nr = r->reply.count;
735                 if(nr > nreq)
736                         nr = nreq;
737
738                 if(type == Tread)
739                         r->b = bl2mem(( uint8_t *)uba, r->b, nr);
740                 else if(cache)
741                         cwrite(c, ( uint8_t *)uba, nr, off);
742
743                 poperror();
744                 mntfree(r);
745                 off += nr;
746                 uba += nr;
747                 cnt += nr;
748                 n -= nr;
749                 if(nr != nreq || n == 0 /*|| current->killed*/)
750                         break;
751         }
752         return cnt;
753 }
754
755 void
756 mountrpc(struct mnt *m, struct mntrpc *r)
757 {
758         char *sn, *cn;
759         int t;
760
761         r->reply.tag = 0;
762         r->reply.type = Tmax;   /* can't ever be a valid message type */
763
764         mountio(m, r);
765
766         t = r->reply.type;
767         switch(t) {
768         case Rerror:
769                 error(r->reply.ename);
770         case Rflush:
771                 error(Eintr);
772         default:
773                 if(t == r->request.type+1)
774                         break;
775                 sn = "?";
776                 if(m->c->name != NULL)
777                         sn = m->c->name->s;
778                 cn = "?";
779                 if(r->c != NULL && r->c->name != NULL)
780                         cn = r->c->name->s;
781                 printd("mnt: proc %s %lud: mismatch from %s %s rep 0x%p tag %d fid %d T%d R%d rp %d\n",
782                        "current->text", "current->pid", sn, cn,
783                         r, r->request.tag, r->request.fid, r->request.type,
784                         r->reply.type, r->reply.tag);
785                 error(Emountrpc);
786         }
787 }
788
789 void
790 mountio(struct mnt *m, struct mntrpc *r)
791 {
792         ERRSTACK(4);
793         int n;
794
795         while(waserror()) {
796                 if(m->rip == current)
797                         mntgate(m);
798                 if(strcmp(current_errstr(), Eintr) != 0){
799                         mntflushfree(m, r);
800                         nexterror();
801                 }
802                 r = mntflushalloc(r, m->msize);
803         }
804
805         spin_lock(&m->lock);
806         r->m = m;
807         r->list = m->queue;
808         m->queue = r;
809         spin_unlock(&m->lock);
810
811         /* Transmit a file system rpc */
812         if(m->msize == 0)
813                 panic("msize");
814         n = convS2M(&r->request, r->rpc, m->msize);
815         if(n < 0)
816                 panic("bad message type in mountio");
817         if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
818                 error(Emountrpc);
819 /*      r->stime = fastticks(NULL); */
820         r->reqlen = n;
821
822         /* Gate readers onto the mount point one at a time */
823         for(;;) {
824                 spin_lock(&m->lock);
825                 if(m->rip == 0)
826                         break;
827                 spin_unlock(&m->lock);
828                 sleep(&r->r, rpcattn, r);
829                 if(r->done){
830                         poperror();
831                         mntflushfree(m, r);
832                         return;
833                 }
834         }
835         m->rip = current;
836         spin_unlock(&m->lock);
837         while(r->done == 0) {
838                 if(mntrpcread(m, r) < 0)
839                         error(Emountrpc);
840                 mountmux(m, r);
841         }
842         mntgate(m);
843         poperror();
844         mntflushfree(m, r);
845 }
846
847 static int
848 doread(struct mnt *m, int len)
849 {
850         struct block *b;
851
852         while(qlen(m->q) < len){
853                 b = devtab[m->c->type]->bread(m->c, m->msize, 0);
854                 if(b == NULL)
855                         return -1;
856                 if(blocklen(b) == 0){
857                         freeblist(b);
858                         return -1;
859                 }
860                 qaddlist(m->q, b);
861         }
862         return 0;
863 }
864
865 int
866 mntrpcread(struct mnt *m, struct mntrpc *r)
867 {
868         int i, t, len, hlen;
869         struct block *b, **l, *nb;
870
871         r->reply.type = 0;
872         r->reply.tag = 0;
873
874         /* read at least length, type, and tag and pullup to a single block */
875         if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
876                 return -1;
877         nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
878
879         /* read in the rest of the message, avoid ridiculous (for now) message sizes */
880         len = GBIT32(nb->rp);
881         if(len > m->msize){
882                 qdiscard(m->q, qlen(m->q));
883                 return -1;
884         }
885         if(doread(m, len) < 0)
886                 return -1;
887
888         /* pullup the header (i.e. everything except data) */
889         t = nb->rp[BIT32SZ];
890         switch(t){
891         case Rread:
892                 hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
893                 break;
894         default:
895                 hlen = len;
896                 break;
897         }
898         nb = pullupqueue(m->q, hlen);
899
900         if(convM2S(nb->rp, len, &r->reply) <= 0){
901                 /* bad message, dump it */
902                 printd("mntrpcread: convM2S failed\n");
903                 qdiscard(m->q, len);
904                 return -1;
905         }
906
907         /* hang the data off of the fcall struct */
908         l = &r->b;
909         *l = NULL;
910         do {
911                 b = qremove(m->q);
912                 if(hlen > 0){
913                         b->rp += hlen;
914                         len -= hlen;
915                         hlen = 0;
916                 }
917                 i = BLEN(b);
918                 if(i <= len){
919                         len -= i;
920                         *l = b;
921                         l = &(b->next);
922                 } else {
923                         /* split block and put unused bit back */
924                         nb = allocb(i-len);
925                         memmove(nb->wp, b->rp+len, i-len);
926                         b->wp = b->rp+len;
927                         nb->wp += i-len;
928                         qputback(m->q, nb);
929                         *l = b;
930                         return 0;
931                 }
932         }while(len > 0);
933
934         return 0;
935 }
936
937 void
938 mntgate(struct mnt *m)
939 {
940         struct mntrpc *q;
941
942         spin_lock(&m->lock);
943         m->rip = 0;
944         for(q = m->queue; q; q = q->list) {
945                 if(q->done == 0)
946                 if(wakeup(&q->r))
947                         break;
948         }
949         spin_unlock(&m->lock);
950 }
951
952 void
953 mountmux(struct mnt *m, struct mntrpc *r)
954 {
955         struct mntrpc **l, *q;
956
957         spin_lock(&m->lock);
958         l = &m->queue;
959         for(q = *l; q; q = q->list) {
960                 /* look for a reply to a message */
961                 if(q->request.tag == r->reply.tag) {
962                         *l = q->list;
963                         if(q != r) {
964                                 /*
965                                  * Completed someone else.
966                                  * Trade pointers to receive buffer.
967                                  */
968                                 q->reply = r->reply;
969                                 q->b = r->b;
970                                 r->b = NULL;
971                         }
972                         q->done = 1;
973                         spin_unlock(&m->lock);
974                         if(mntstats != NULL)
975                                 (*mntstats)(q->request.type,
976                                         m->c, q->stime,
977                                         q->reqlen + r->replen);
978                         if(q != r)
979                                 wakeup(&q->r);
980                         return;
981                 }
982                 l = &q->list;
983         }
984         spin_unlock(&m->lock);
985         if(r->reply.type == Rerror){
986                 printd("unexpected reply tag %ud; type %d (error %q)\n", r->reply.tag, r->reply.type, r->reply.ename);
987         }else{
988                 printd("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
989         }
990 }
991
992 /*
993  * Create a new flush request and chain the previous
994  * requests from it
995  */
996 struct mntrpc*
997 mntflushalloc(struct mntrpc *r, uint32_t iounit)
998 {
999         struct mntrpc *fr;
1000
1001         fr = mntralloc(0, iounit);
1002
1003         fr->request.type = Tflush;
1004         if(r->request.type == Tflush)
1005                 fr->request.oldtag = r->request.oldtag;
1006         else
1007                 fr->request.oldtag = r->request.tag;
1008         fr->flushed = r;
1009
1010         return fr;
1011 }
1012
1013 /*
1014  *  Free a chain of flushes.  Remove each unanswered
1015  *  flush and the original message from the unanswered
1016  *  request queue.  Mark the original message as done
1017  *  and if it hasn't been answered set the reply to to
1018  *  Rflush.
1019  */
1020 void
1021 mntflushfree(struct mnt *m, struct mntrpc *r)
1022 {
1023         struct mntrpc *fr;
1024
1025         while(r){
1026                 fr = r->flushed;
1027                 if(!r->done){
1028                         r->reply.type = Rflush;
1029                         mntqrm(m, r);
1030                 }
1031                 if(fr)
1032                         mntfree(r);
1033                 r = fr;
1034         }
1035 }
1036
1037 static int
1038 alloctag(void)
1039 {
1040         int i, j;
1041         uint32_t v;
1042
1043         for(i = 0; i < NMASK; i++){
1044                 v = mntalloc.tagmask[i];
1045                 if(v == ~0UL)
1046                         continue;
1047                 for(j = 0; j < 1<<TAGSHIFT; j++)
1048                         if((v & (1<<j)) == 0){
1049                                 mntalloc.tagmask[i] |= 1<<j;
1050                                 return (i<<TAGSHIFT) + j;
1051                         }
1052         }
1053         /* panic("no devmnt tags left"); */
1054         return NOTAG;
1055 }
1056
1057 static void
1058 freetag(int t)
1059 {
1060         mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1061 }
1062
1063 struct mntrpc*
1064 mntralloc(struct chan *c, uint32_t msize)
1065 {
1066         struct mntrpc *new;
1067
1068         spin_lock(&mntalloc.l);
1069         new = mntalloc.rpcfree;
1070         if(new == NULL){
1071                 new = kzmalloc(sizeof(struct mntrpc), 0);
1072                 if(new == NULL) {
1073                         spin_unlock(&mntalloc.l);
1074                         exhausted("mount rpc header");
1075                 }
1076                 /*
1077                  * The header is split from the data buffer as
1078                  * mountmux may swap the buffer with another header.
1079                  */
1080                 new->rpc = mallocz(msize, 0);
1081                 if(new->rpc == NULL){
1082                         kfree(new);
1083                         spin_unlock(&mntalloc.l);
1084                         exhausted("mount rpc buffer");
1085                 }
1086                 new->rpclen = msize;
1087                 new->request.tag = alloctag();
1088                 if(new->request.tag == NOTAG){
1089                         kfree(new);
1090                         spin_unlock(&mntalloc.l);
1091                         exhausted("rpc tags");
1092                 }
1093         }
1094         else {
1095                 mntalloc.rpcfree = new->list;
1096                 mntalloc.nrpcfree--;
1097                 if(new->rpclen < msize){
1098                         kfree(new->rpc);
1099                         new->rpc = mallocz(msize, 0);
1100                         if(new->rpc == NULL){
1101                                 kfree(new);
1102                                 mntalloc.nrpcused--;
1103                                 spin_unlock(&mntalloc.l);
1104                                 exhausted("mount rpc buffer");
1105                         }
1106                         new->rpclen = msize;
1107                 }
1108         }
1109         mntalloc.nrpcused++;
1110         spin_unlock(&mntalloc.l);
1111         new->c = c;
1112         new->done = 0;
1113         new->flushed = NULL;
1114         new->b = NULL;
1115         return new;
1116 }
1117
1118 void
1119 mntfree(struct mntrpc *r)
1120 {
1121         if(r->b != NULL)
1122                 freeblist(r->b);
1123         spin_lock(&mntalloc.l);
1124         if(mntalloc.nrpcfree >= 10){
1125                 kfree(r->rpc);
1126                 freetag(r->request.tag);
1127                 kfree(r);
1128         }
1129         else{
1130                 r->list = mntalloc.rpcfree;
1131                 mntalloc.rpcfree = r;
1132                 mntalloc.nrpcfree++;
1133         }
1134         mntalloc.nrpcused--;
1135         spin_unlock(&mntalloc.l);
1136 }
1137
1138 void
1139 mntqrm(struct mnt *m, struct mntrpc *r)
1140 {
1141         struct mntrpc **l, *f;
1142
1143         spin_lock(&m->lock);
1144         r->done = 1;
1145
1146         l = &m->queue;
1147         for(f = *l; f; f = f->list) {
1148                 if(f == r) {
1149                         *l = r->list;
1150                         break;
1151                 }
1152                 l = &f->list;
1153         }
1154         spin_unlock(&m->lock);
1155 }
1156
1157 struct mnt*
1158 mntchk(struct chan *c)
1159 {
1160         struct mnt *m;
1161
1162         /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1163
1164         if(c->mchan == NULL)
1165                 panic("mntchk 1: NULL mchan c %s\n", /*c2name(c)*/"channame?");
1166
1167         m = c->mchan->mux;
1168
1169         if(m == NULL)
1170                 printd("mntchk 2: NULL mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan));
1171
1172         /*
1173          * Was it closed and reused (was error(Eshutdown); now, it can't happen)
1174          */
1175         if(m->id == 0 || m->id >= c->dev)
1176                 panic("mntchk 3: can't happen");
1177
1178         return m;
1179 }
1180
1181 /*
1182  * Rewrite channel type and dev for in-flight data to
1183  * reflect local values.  These entries are known to be
1184  * the first two in the Dir encoding after the count.
1185  */
1186 void
1187 mntdirfix(uint8_t *dirbuf, struct chan *c)
1188 {
1189         unsigned int r;
1190
1191         r = devtab[c->type]->dc;
1192         dirbuf += BIT16SZ;      /* skip count */
1193         PBIT16(dirbuf, r);
1194         dirbuf += BIT16SZ;
1195         PBIT32(dirbuf, c->dev);
1196 }
1197
1198 int
1199 rpcattn(void *v)
1200 {
1201         struct mntrpc *r;
1202
1203         r = v;
1204         return r->done || r->m->rip == 0;
1205 }
1206
1207 struct dev mntdevtab = {
1208         'M',
1209         "mnt",
1210
1211         mntinit,
1212         mntattach,
1213         mntwalk,
1214         mntstat,
1215         mntopen,
1216         mntcreate,
1217         mntclose,
1218         mntread,
1219         devbread,
1220         mntwrite,
1221         devbwrite,
1222         mntremove,
1223         mntwstat,
1224 };