Export CONFIG_ options via #version/kconfig
[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 <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 long mntrdwr(int unused_int, struct chan *, void *, long, int64_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                                                            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 int mntstat(struct chan *c, uint8_t * dp, int 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 {
593         mntopencreate(Tcreate, c, name, omode, perm);
594 }
595
596 static void mntclunk(struct chan *c, int t)
597 {
598         ERRSTACK(1);
599         struct mnt *m;
600         struct mntrpc *r;
601
602         m = mntchk(c);
603         r = mntralloc(c, m->msize);
604         if (waserror()) {
605                 mntfree(r);
606                 nexterror();
607         }
608
609         r->request.type = t;
610         r->request.fid = c->fid;
611         mountrpc(m, r);
612         mntfree(r);
613         poperror();
614 }
615
616 void muxclose(struct mnt *m)
617 {
618         struct mntrpc *q, *r;
619
620         for (q = m->queue; q; q = r) {
621                 r = q->list;
622                 mntfree(q);
623         }
624         m->id = 0;
625         kfree(m->version);
626         m->version = NULL;
627         mntpntfree(m);
628 }
629
630 void mntpntfree(struct mnt *m)
631 {
632         struct mnt *f, **l;
633         struct queue *q;
634
635         spin_lock(&mntalloc.l);
636         l = &mntalloc.list;
637         for (f = *l; f; f = f->list) {
638                 if (f == m) {
639                         *l = m->list;
640                         break;
641                 }
642                 l = &f->list;
643         }
644         m->list = mntalloc.mntfree;
645         mntalloc.mntfree = m;
646         q = m->q;
647         spin_unlock(&mntalloc.l);
648
649         qfree(q);
650 }
651
652 static void mntclose(struct chan *c)
653 {
654         mntclunk(c, Tclunk);
655 }
656
657 static void mntremove(struct chan *c)
658 {
659         mntclunk(c, Tremove);
660 }
661
662 static int mntwstat(struct chan *c, uint8_t * dp, int n)
663 {
664         ERRSTACK(1);
665         struct mnt *m;
666         struct mntrpc *r;
667
668         m = mntchk(c);
669         r = mntralloc(c, m->msize);
670         if (waserror()) {
671                 mntfree(r);
672                 nexterror();
673         }
674         r->request.type = Twstat;
675         r->request.fid = c->fid;
676         r->request.nstat = n;
677         r->request.stat = dp;
678         mountrpc(m, r);
679         poperror();
680         mntfree(r);
681         return n;
682 }
683
684 /* the servers should either return units of whole directory entries
685  * OR support seeking to an arbitrary place. One or other.
686  * Both are fine, but at least one is a minimum.
687  * If the return a partial result, but more than one result,
688  * we'll return a shorter read and the next offset will be aligned
689  */
690 static long mntread(struct chan *c, void *buf, long n, int64_t off)
691 {
692         uint8_t *p, *e;
693         int nc, cache, isdir, dirlen;
694         int numdirent = 0;
695
696         isdir = 0;
697         cache = c->flag & CCACHE;
698         if (c->qid.type & QTDIR) {
699                 cache = 0;
700                 isdir = 1;
701         }
702
703         p = buf;
704         if (cache) {
705                 nc = cread(c, buf, n, off);
706                 if (nc > 0) {
707                         n -= nc;
708                         if (n == 0)
709                                 return nc;
710                         p += nc;
711                         off += nc;
712                 }
713                 n = mntrdwr(Tread, c, p, n, off);
714                 cupdate(c, p, n, off);
715                 return n + nc;
716         }
717
718         n = mntrdwr(Tread, c, buf, n, off);
719
720         if (isdir) {
721                 for (e = &p[n]; p + BIT16SZ < e; p += dirlen) {
722                         dirlen = BIT16SZ + GBIT16(p);
723                         if (p + dirlen > e){
724                                 break;
725                         }
726                         validstat(p, dirlen, 0);
727                         mntdirfix(p, c);
728                         numdirent += dirlen;
729                 }
730                 if (p != e) {
731                         //error(Esbadstat);
732                         /* not really. Maybe the server supports
733                          * arbitrary seek like go9p now does.
734                          */
735                         n = numdirent;
736                 }
737         }
738         return n;
739 }
740
741 static long mntwrite(struct chan *c, void *buf, long n, int64_t off)
742 {
743         return mntrdwr(Twrite, c, buf, n, off);
744 }
745
746 long mntrdwr(int type, struct chan *c, void *buf, long n, int64_t off)
747 {
748         ERRSTACK(1);
749         struct mnt *m;
750         struct mntrpc *r;                       /* TO DO: volatile struct { Mntrpc *r; } r; */
751         char *uba;
752         int cache;
753         uint32_t cnt, nr, nreq;
754
755         m = mntchk(c);
756         uba = buf;
757         cnt = 0;
758         cache = c->flag & CCACHE;
759         if (c->qid.type & QTDIR)
760                 cache = 0;
761         for (;;) {
762                 r = mntralloc(c, m->msize);
763                 if (waserror()) {
764                         mntfree(r);
765                         nexterror();
766                 }
767                 r->request.type = type;
768                 r->request.fid = c->fid;
769                 r->request.offset = off;
770                 r->request.data = uba;
771                 nr = n;
772                 if (nr > m->msize - IOHDRSZ)
773                         nr = m->msize - IOHDRSZ;
774                 r->request.count = nr;
775                 mountrpc(m, r);
776                 nreq = r->request.count;
777                 nr = r->reply.count;
778                 if (nr > nreq)
779                         nr = nreq;
780
781                 if (type == Tread)
782                         r->b = bl2mem((uint8_t *) uba, r->b, nr);
783                 else if (cache)
784                         cwrite(c, (uint8_t *) uba, nr, off);
785
786                 poperror();
787                 mntfree(r);
788                 off += nr;
789                 uba += nr;
790                 cnt += nr;
791                 n -= nr;
792                 if (nr != nreq || n == 0 /*|| current->killed */ )
793                         break;
794         }
795         return cnt;
796 }
797
798 void mountrpc(struct mnt *m, struct mntrpc *r)
799 {
800         char *sn, *cn;
801         int t;
802         char *e;
803
804         r->reply.tag = 0;
805         r->reply.type = Tmax;   /* can't ever be a valid message type */
806
807         mountio(m, r);
808
809         t = r->reply.type;
810         switch (t) {
811                 case Rerror:
812                         /* in Akaros mode, first four characters
813                          * are errno.
814                          */
815                         e = r->reply.ename;
816                         /* If it is in the format "XXXX <at least one char>" */
817                         if ((strlen(e) > 5) && isxdigit(e[0]) &&
818                                 isxdigit(e[1]) &&
819                                 isxdigit(e[2]) &&
820                                 isxdigit(e[3])) {
821
822                                 int errno = strtoul(e, NULL, 16);
823
824                                 error(errno, &r->reply.ename[5]);
825                         } else
826                                 error(EFAIL, r->reply.ename);
827                 case Rflush:
828                         error(EINTR, ERROR_FIXME);
829                 default:
830                         if (t == r->request.type + 1)
831                                 break;
832                         sn = "?";
833                         if (m->c->name != NULL)
834                                 sn = m->c->name->s;
835                         cn = "?";
836                         if (r->c != NULL && r->c->name != NULL)
837                                 cn = r->c->name->s;
838                         printk
839                                 ("mnt: proc %s %lu: mismatch from %s %s rep 0x%p tag %d fid %d T%d R%d rp %d\n",
840                                  "current->text", "current->pid", sn, cn, r, r->request.tag,
841                                  r->request.fid, r->request.type, r->reply.type, r->reply.tag);
842                         error(EPROTO, ERROR_FIXME);
843         }
844 }
845
846 void mountio(struct mnt *m, struct mntrpc *r)
847 {
848         ERRSTACK(1);
849         int n;
850
851         while (waserror()) {
852                 if (m->rip == current)
853                         mntgate(m);
854                 /* Syscall aborts are like Plan 9 Eintr.  For those, we need to change
855                  * the old request to a flsh (mntflushalloc) and try again.  We'll
856                  * always try to flush, and you can't get out until the flush either
857                  * succeeds or errors out with a non-abort/Eintr error.
858                  *
859                  * This all means that regular aborts cannot break us out of here!  We
860                  * can consider that policy in the future, if we need to.  Regardless,
861                  * if the process is dying, we really do need to abort. */
862                 if ((get_errno() != EINTR) || proc_is_dying(current)) {
863                         /* all other errors or dying, bail out! */
864                         mntflushfree(m, r);
865                         nexterror();
866                 }
867                 /* try again.  this is where you can get the "rpc tags" errstr. */
868                 r = mntflushalloc(r, m->msize);
869                 /* need one for every waserror call (so this plus one outside) */
870                 poperror();
871         }
872
873         spin_lock(&m->lock);
874         r->m = m;
875         r->list = m->queue;
876         m->queue = r;
877         spin_unlock(&m->lock);
878
879         /* Transmit a file system rpc */
880         if (m->msize == 0)
881                 panic("msize");
882         n = convS2M(&r->request, r->rpc, m->msize);
883         if (n < 0)
884                 panic("bad message type in mountio");
885         if (devtab[m->c->type].write(m->c, r->rpc, n, 0) != n)
886                 error(EIO, ERROR_FIXME);
887 /*      r->stime = fastticks(NULL); */
888         r->reqlen = n;
889
890         /* Gate readers onto the mount point one at a time */
891         for (;;) {
892                 spin_lock(&m->lock);
893                 if (m->rip == 0)
894                         break;
895                 spin_unlock(&m->lock);
896                 rendez_sleep(&r->r, rpcattn, r);
897                 if (r->done) {
898                         poperror();
899                         mntflushfree(m, r);
900                         return;
901                 }
902         }
903         m->rip = current;
904         spin_unlock(&m->lock);
905         while (r->done == 0) {
906                 if (mntrpcread(m, r) < 0)
907                         error(EIO, ERROR_FIXME);
908                 mountmux(m, r);
909         }
910         mntgate(m);
911         poperror();
912         mntflushfree(m, r);
913 }
914
915 static int doread(struct mnt *m, int len)
916 {
917         struct block *b;
918
919         while (qlen(m->q) < len) {
920                 b = devtab[m->c->type].bread(m->c, m->msize, 0);
921                 if (b == NULL)
922                         return -1;
923                 if (blocklen(b) == 0) {
924                         freeblist(b);
925                         return -1;
926                 }
927                 qaddlist(m->q, b);
928         }
929         return 0;
930 }
931
932 int mntrpcread(struct mnt *m, struct mntrpc *r)
933 {
934         int i, t, len, hlen;
935         struct block *b, **l, *nb;
936
937         r->reply.type = 0;
938         r->reply.tag = 0;
939
940         /* read at least length, type, and tag and pullup to a single block */
941         if (doread(m, BIT32SZ + BIT8SZ + BIT16SZ) < 0)
942                 return -1;
943         nb = pullupqueue(m->q, BIT32SZ + BIT8SZ + BIT16SZ);
944
945         /* read in the rest of the message, avoid ridiculous (for now) message sizes */
946         len = GBIT32(nb->rp);
947         if (len > m->msize) {
948                 qdiscard(m->q, qlen(m->q));
949                 return -1;
950         }
951         if (doread(m, len) < 0)
952                 return -1;
953
954         /* pullup the header (i.e. everything except data) */
955         t = nb->rp[BIT32SZ];
956         switch (t) {
957                 case Rread:
958                         hlen = BIT32SZ + BIT8SZ + BIT16SZ + BIT32SZ;
959                         break;
960                 default:
961                         hlen = len;
962                         break;
963         }
964         nb = pullupqueue(m->q, hlen);
965
966         if (convM2S(nb->rp, len, &r->reply) <= 0) {
967                 /* bad message, dump it */
968                 printd("mntrpcread: convM2S failed\n");
969                 qdiscard(m->q, len);
970                 return -1;
971         }
972
973         /* TODO: this should use a qio helper directly.  qputback should have the
974          * qlocked, but I guess we assume we're the only one using it. */
975
976         /* hang the data off of the fcall struct */
977         l = &r->b;
978         *l = NULL;
979         do {
980                 b = qget(m->q);
981                 /* TODO: have better block helpers for this and the memmove below */
982                 b = linearizeblock(b);
983                 if (hlen > 0) {
984                         b->rp += hlen;
985                         len -= hlen;
986                         hlen = 0;
987                 }
988                 i = BLEN(b);
989                 if (i <= len) {
990                         len -= i;
991                         *l = b;
992                         l = &(b->next);
993                 } else {
994                         /* split block and put unused bit back */
995                         nb = block_alloc(i - len, MEM_WAIT);
996                         memmove(nb->wp, b->rp + len, i - len);
997                         b->wp = b->rp + len;
998                         nb->wp += i - len;
999                         qputback(m->q, nb);
1000                         *l = b;
1001                         return 0;
1002                 }
1003         } while (len > 0);
1004
1005         return 0;
1006 }
1007
1008 void mntgate(struct mnt *m)
1009 {
1010         struct mntrpc *q;
1011
1012         spin_lock(&m->lock);
1013         m->rip = 0;
1014         for (q = m->queue; q; q = q->list) {
1015                 if (q->done == 0)
1016                         if (rendez_wakeup(&q->r))
1017                                 break;
1018         }
1019         spin_unlock(&m->lock);
1020 }
1021
1022 void mountmux(struct mnt *m, struct mntrpc *r)
1023 {
1024         struct mntrpc **l, *q;
1025
1026         spin_lock(&m->lock);
1027         l = &m->queue;
1028         for (q = *l; q; q = q->list) {
1029                 /* look for a reply to a message */
1030                 if (q->request.tag == r->reply.tag) {
1031                         *l = q->list;
1032                         if (q != r) {
1033                                 /*
1034                                  * Completed someone else.
1035                                  * Trade pointers to receive buffer.
1036                                  */
1037                                 q->reply = r->reply;
1038                                 q->b = r->b;
1039                                 r->b = NULL;
1040                         }
1041                         q->done = 1;
1042                         spin_unlock(&m->lock);
1043                         if (mntstats != NULL)
1044                                 (*mntstats) (q->request.type,
1045                                                          m->c, q->stime, q->reqlen + r->replen);
1046                         if (q != r)
1047                                 rendez_wakeup(&q->r);
1048                         return;
1049                 }
1050                 l = &q->list;
1051         }
1052         spin_unlock(&m->lock);
1053         if (r->reply.type == Rerror) {
1054                 printd("unexpected reply tag %u; type %d (error %q)\n", r->reply.tag,
1055                            r->reply.type, r->reply.ename);
1056         } else {
1057                 printd("unexpected reply tag %u; type %d\n", r->reply.tag,
1058                            r->reply.type);
1059         }
1060 }
1061
1062 /*
1063  * Create a new flush request and chain the previous
1064  * requests from it
1065  */
1066 struct mntrpc *mntflushalloc(struct mntrpc *r, uint32_t iounit)
1067 {
1068         struct mntrpc *fr;
1069
1070         fr = mntralloc(0, iounit);
1071
1072         fr->request.type = Tflush;
1073         if (r->request.type == Tflush)
1074                 fr->request.oldtag = r->request.oldtag;
1075         else
1076                 fr->request.oldtag = r->request.tag;
1077         fr->flushed = r;
1078
1079         return fr;
1080 }
1081
1082 /*
1083  *  Free a chain of flushes.  Remove each unanswered
1084  *  flush and the original message from the unanswered
1085  *  request queue.  Mark the original message as done
1086  *  and if it hasn't been answered set the reply to to
1087  *  Rflush.
1088  */
1089 void mntflushfree(struct mnt *m, struct mntrpc *r)
1090 {
1091         struct mntrpc *fr;
1092
1093         while (r) {
1094                 fr = r->flushed;
1095                 if (!r->done) {
1096                         r->reply.type = Rflush;
1097                         mntqrm(m, r);
1098                 }
1099                 if (fr)
1100                         mntfree(r);
1101                 r = fr;
1102         }
1103 }
1104
1105 static int alloctag(void)
1106 {
1107         return get_u16(mntalloc.tags);
1108 }
1109
1110 static void freetag(int t)
1111 {
1112         put_u16(mntalloc.tags, t);
1113 }
1114
1115 struct mntrpc *mntralloc(struct chan *c, uint32_t msize)
1116 {
1117         struct mntrpc *new;
1118
1119         spin_lock(&mntalloc.l);
1120         new = mntalloc.rpcfree;
1121         if (new == NULL) {
1122                 new = kzmalloc(sizeof(struct mntrpc), 0);
1123                 if (new == NULL) {
1124                         spin_unlock(&mntalloc.l);
1125                         exhausted("mount rpc header");
1126                 }
1127                 rendez_init(&new->r);
1128                 /*
1129                  * The header is split from the data buffer as
1130                  * mountmux may swap the buffer with another header.
1131                  */
1132                 new->rpc = kzmalloc(msize, MEM_WAIT);
1133                 if (new->rpc == NULL) {
1134                         kfree(new);
1135                         spin_unlock(&mntalloc.l);
1136                         exhausted("mount rpc buffer");
1137                 }
1138                 new->rpclen = msize;
1139                 new->request.tag = alloctag();
1140                 if (new->request.tag == NOTAG) {
1141                         kfree(new);
1142                         spin_unlock(&mntalloc.l);
1143                         exhausted("rpc tags");
1144                 }
1145         } else {
1146                 mntalloc.rpcfree = new->list;
1147                 mntalloc.nrpcfree--;
1148                 if (new->rpclen < msize) {
1149                         kfree(new->rpc);
1150                         new->rpc = kzmalloc(msize, MEM_WAIT);
1151                         if (new->rpc == NULL) {
1152                                 kfree(new);
1153                                 mntalloc.nrpcused--;
1154                                 spin_unlock(&mntalloc.l);
1155                                 exhausted("mount rpc buffer");
1156                         }
1157                         new->rpclen = msize;
1158                 }
1159         }
1160         mntalloc.nrpcused++;
1161         spin_unlock(&mntalloc.l);
1162         new->c = c;
1163         new->done = 0;
1164         new->flushed = NULL;
1165         new->b = NULL;
1166         return new;
1167 }
1168
1169 void mntfree(struct mntrpc *r)
1170 {
1171         if (r->b != NULL)
1172                 freeblist(r->b);
1173         spin_lock(&mntalloc.l);
1174         if (mntalloc.nrpcfree >= 10) {
1175                 kfree(r->rpc);
1176                 freetag(r->request.tag);
1177                 kfree(r);
1178         } else {
1179                 r->list = mntalloc.rpcfree;
1180                 mntalloc.rpcfree = r;
1181                 mntalloc.nrpcfree++;
1182         }
1183         mntalloc.nrpcused--;
1184         spin_unlock(&mntalloc.l);
1185 }
1186
1187 void mntqrm(struct mnt *m, struct mntrpc *r)
1188 {
1189         struct mntrpc **l, *f;
1190
1191         spin_lock(&m->lock);
1192         r->done = 1;
1193
1194         l = &m->queue;
1195         for (f = *l; f; f = f->list) {
1196                 if (f == r) {
1197                         *l = r->list;
1198                         break;
1199                 }
1200                 l = &f->list;
1201         }
1202         spin_unlock(&m->lock);
1203 }
1204
1205 struct mnt *mntchk(struct chan *c)
1206 {
1207         struct mnt *m;
1208
1209         /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1210
1211         if (c->mchan == NULL)
1212                 panic("mntchk 1: NULL mchan c %s\n", /*c2name(c) */ "channame?");
1213
1214         m = c->mchan->mux;
1215
1216         if (m == NULL)
1217                 printd("mntchk 2: NULL mux c %s c->mchan %s \n", c2name(c),
1218                            c2name(c->mchan));
1219
1220         /*
1221          * Was it closed and reused (was error(Eshutdown); now, it can't happen)
1222          */
1223         if (m->id == 0 || m->id >= c->dev)
1224                 panic("mntchk 3: can't happen");
1225
1226         return m;
1227 }
1228
1229 /*
1230  * Rewrite channel type and dev for in-flight data to
1231  * reflect local values.  These entries are known to be
1232  * the first two in the Dir encoding after the count.
1233  */
1234 void mntdirfix(uint8_t * dirbuf, struct chan *c)
1235 {
1236         /* TODO: We used to use the device's char (dc), instead of the type.  not
1237          * sure about the effects one way or the other.  This might be the type[2]
1238          * and dev[4] in a D (struct dir, see 9p's stat
1239          * (http://man.cat-v.org/plan_9/5/stat).  In which case, those should be for
1240          * the kernel's use.  Hopefully our kernel. */
1241         dirbuf += BIT16SZ;      /* skip count */
1242         PBIT16(dirbuf, c->type);
1243         dirbuf += BIT16SZ;
1244         PBIT32(dirbuf, c->dev);
1245 }
1246
1247 int rpcattn(void *v)
1248 {
1249         struct mntrpc *r;
1250
1251         r = v;
1252         return r->done || r->m->rip == 0;
1253 }
1254
1255 struct dev mntdevtab __devtab = {
1256         .name = "mnt",
1257
1258         .reset = devreset,
1259         .init = mntinit,
1260         .shutdown = devshutdown,
1261         .attach = mntattach,
1262         .walk = mntwalk,
1263         .stat = mntstat,
1264         .open = mntopen,
1265         .create = mntcreate,
1266         .close = mntclose,
1267         .read = mntread,
1268         .bread = devbread,
1269         .write = mntwrite,
1270         .bwrite = devbwrite,
1271         .remove = mntremove,
1272         .wstat = mntwstat,
1273         .power = devpower,
1274         .chaninfo = devchaninfo,
1275 };