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