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