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