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