Use the new RNG for the networking stack
[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;
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;
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                                   KMALLOC_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                         printd
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                 if (get_errno() != EINTR) {
859                         /* all other errors (not abort or Eintr) */
860                         mntflushfree(m, r);
861                         nexterror();
862                 }
863                 r = mntflushalloc(r, m->msize);
864                 /* need one for every waserror call (so this plus one outside) */
865                 poperror();
866         }
867
868         spin_lock(&m->lock);
869         r->m = m;
870         r->list = m->queue;
871         m->queue = r;
872         spin_unlock(&m->lock);
873
874         /* Transmit a file system rpc */
875         if (m->msize == 0)
876                 panic("msize");
877         n = convS2M(&r->request, r->rpc, m->msize);
878         if (n < 0)
879                 panic("bad message type in mountio");
880         if (devtab[m->c->type].write(m->c, r->rpc, n, 0) != n)
881                 error(EIO, ERROR_FIXME);
882 /*      r->stime = fastticks(NULL); */
883         r->reqlen = n;
884
885         /* Gate readers onto the mount point one at a time */
886         for (;;) {
887                 spin_lock(&m->lock);
888                 if (m->rip == 0)
889                         break;
890                 spin_unlock(&m->lock);
891                 rendez_sleep(&r->r, rpcattn, r);
892                 if (r->done) {
893                         poperror();
894                         mntflushfree(m, r);
895                         return;
896                 }
897         }
898         m->rip = current;
899         spin_unlock(&m->lock);
900         while (r->done == 0) {
901                 if (mntrpcread(m, r) < 0)
902                         error(EIO, ERROR_FIXME);
903                 mountmux(m, r);
904         }
905         mntgate(m);
906         poperror();
907         mntflushfree(m, r);
908 }
909
910 static int doread(struct mnt *m, int len)
911 {
912         struct block *b;
913
914         while (qlen(m->q) < len) {
915                 b = devtab[m->c->type].bread(m->c, m->msize, 0);
916                 if (b == NULL)
917                         return -1;
918                 if (blocklen(b) == 0) {
919                         freeblist(b);
920                         return -1;
921                 }
922                 qaddlist(m->q, b);
923         }
924         return 0;
925 }
926
927 int mntrpcread(struct mnt *m, struct mntrpc *r)
928 {
929         int i, t, len, hlen;
930         struct block *b, **l, *nb;
931
932         r->reply.type = 0;
933         r->reply.tag = 0;
934
935         /* read at least length, type, and tag and pullup to a single block */
936         if (doread(m, BIT32SZ + BIT8SZ + BIT16SZ) < 0)
937                 return -1;
938         nb = pullupqueue(m->q, BIT32SZ + BIT8SZ + BIT16SZ);
939
940         /* read in the rest of the message, avoid ridiculous (for now) message sizes */
941         len = GBIT32(nb->rp);
942         if (len > m->msize) {
943                 qdiscard(m->q, qlen(m->q));
944                 return -1;
945         }
946         if (doread(m, len) < 0)
947                 return -1;
948
949         /* pullup the header (i.e. everything except data) */
950         t = nb->rp[BIT32SZ];
951         switch (t) {
952                 case Rread:
953                         hlen = BIT32SZ + BIT8SZ + BIT16SZ + BIT32SZ;
954                         break;
955                 default:
956                         hlen = len;
957                         break;
958         }
959         nb = pullupqueue(m->q, hlen);
960
961         if (convM2S(nb->rp, len, &r->reply) <= 0) {
962                 /* bad message, dump it */
963                 printd("mntrpcread: convM2S failed\n");
964                 qdiscard(m->q, len);
965                 return -1;
966         }
967
968         /* hang the data off of the fcall struct */
969         l = &r->b;
970         *l = NULL;
971         do {
972                 b = qremove(m->q);
973                 /* TODO: have better block helpers for this and the memmove below */
974                 b = linearizeblock(b);
975                 if (hlen > 0) {
976                         b->rp += hlen;
977                         len -= hlen;
978                         hlen = 0;
979                 }
980                 i = BLEN(b);
981                 if (i <= len) {
982                         len -= i;
983                         *l = b;
984                         l = &(b->next);
985                 } else {
986                         /* split block and put unused bit back */
987                         nb = allocb(i - len);
988                         memmove(nb->wp, b->rp + len, i - len);
989                         b->wp = b->rp + len;
990                         nb->wp += i - len;
991                         qputback(m->q, nb);
992                         *l = b;
993                         return 0;
994                 }
995         } while (len > 0);
996
997         return 0;
998 }
999
1000 void mntgate(struct mnt *m)
1001 {
1002         struct mntrpc *q;
1003
1004         spin_lock(&m->lock);
1005         m->rip = 0;
1006         for (q = m->queue; q; q = q->list) {
1007                 if (q->done == 0)
1008                         if (rendez_wakeup(&q->r))
1009                                 break;
1010         }
1011         spin_unlock(&m->lock);
1012 }
1013
1014 void mountmux(struct mnt *m, struct mntrpc *r)
1015 {
1016         struct mntrpc **l, *q;
1017
1018         spin_lock(&m->lock);
1019         l = &m->queue;
1020         for (q = *l; q; q = q->list) {
1021                 /* look for a reply to a message */
1022                 if (q->request.tag == r->reply.tag) {
1023                         *l = q->list;
1024                         if (q != r) {
1025                                 /*
1026                                  * Completed someone else.
1027                                  * Trade pointers to receive buffer.
1028                                  */
1029                                 q->reply = r->reply;
1030                                 q->b = r->b;
1031                                 r->b = NULL;
1032                         }
1033                         q->done = 1;
1034                         spin_unlock(&m->lock);
1035                         if (mntstats != NULL)
1036                                 (*mntstats) (q->request.type,
1037                                                          m->c, q->stime, q->reqlen + r->replen);
1038                         if (q != r)
1039                                 rendez_wakeup(&q->r);
1040                         return;
1041                 }
1042                 l = &q->list;
1043         }
1044         spin_unlock(&m->lock);
1045         if (r->reply.type == Rerror) {
1046                 printd("unexpected reply tag %u; type %d (error %q)\n", r->reply.tag,
1047                            r->reply.type, r->reply.ename);
1048         } else {
1049                 printd("unexpected reply tag %u; type %d\n", r->reply.tag,
1050                            r->reply.type);
1051         }
1052 }
1053
1054 /*
1055  * Create a new flush request and chain the previous
1056  * requests from it
1057  */
1058 struct mntrpc *mntflushalloc(struct mntrpc *r, uint32_t iounit)
1059 {
1060         struct mntrpc *fr;
1061
1062         fr = mntralloc(0, iounit);
1063
1064         fr->request.type = Tflush;
1065         if (r->request.type == Tflush)
1066                 fr->request.oldtag = r->request.oldtag;
1067         else
1068                 fr->request.oldtag = r->request.tag;
1069         fr->flushed = r;
1070
1071         return fr;
1072 }
1073
1074 /*
1075  *  Free a chain of flushes.  Remove each unanswered
1076  *  flush and the original message from the unanswered
1077  *  request queue.  Mark the original message as done
1078  *  and if it hasn't been answered set the reply to to
1079  *  Rflush.
1080  */
1081 void mntflushfree(struct mnt *m, struct mntrpc *r)
1082 {
1083         struct mntrpc *fr;
1084
1085         while (r) {
1086                 fr = r->flushed;
1087                 if (!r->done) {
1088                         r->reply.type = Rflush;
1089                         mntqrm(m, r);
1090                 }
1091                 if (fr)
1092                         mntfree(r);
1093                 r = fr;
1094         }
1095 }
1096
1097 static int alloctag(void)
1098 {
1099         return get_u16(mntalloc.tags);
1100 }
1101
1102 static void freetag(int t)
1103 {
1104         put_u16(mntalloc.tags, t);
1105 }
1106
1107 struct mntrpc *mntralloc(struct chan *c, uint32_t msize)
1108 {
1109         struct mntrpc *new;
1110
1111         spin_lock(&mntalloc.l);
1112         new = mntalloc.rpcfree;
1113         if (new == NULL) {
1114                 new = kzmalloc(sizeof(struct mntrpc), 0);
1115                 if (new == NULL) {
1116                         spin_unlock(&mntalloc.l);
1117                         exhausted("mount rpc header");
1118                 }
1119                 rendez_init(&new->r);
1120                 /*
1121                  * The header is split from the data buffer as
1122                  * mountmux may swap the buffer with another header.
1123                  */
1124                 new->rpc = kzmalloc(msize, KMALLOC_WAIT);
1125                 if (new->rpc == NULL) {
1126                         kfree(new);
1127                         spin_unlock(&mntalloc.l);
1128                         exhausted("mount rpc buffer");
1129                 }
1130                 new->rpclen = msize;
1131                 new->request.tag = alloctag();
1132                 if (new->request.tag == NOTAG) {
1133                         kfree(new);
1134                         spin_unlock(&mntalloc.l);
1135                         exhausted("rpc tags");
1136                 }
1137         } else {
1138                 mntalloc.rpcfree = new->list;
1139                 mntalloc.nrpcfree--;
1140                 if (new->rpclen < msize) {
1141                         kfree(new->rpc);
1142                         new->rpc = kzmalloc(msize, KMALLOC_WAIT);
1143                         if (new->rpc == NULL) {
1144                                 kfree(new);
1145                                 mntalloc.nrpcused--;
1146                                 spin_unlock(&mntalloc.l);
1147                                 exhausted("mount rpc buffer");
1148                         }
1149                         new->rpclen = msize;
1150                 }
1151         }
1152         mntalloc.nrpcused++;
1153         spin_unlock(&mntalloc.l);
1154         new->c = c;
1155         new->done = 0;
1156         new->flushed = NULL;
1157         new->b = NULL;
1158         return new;
1159 }
1160
1161 void mntfree(struct mntrpc *r)
1162 {
1163         if (r->b != NULL)
1164                 freeblist(r->b);
1165         spin_lock(&mntalloc.l);
1166         if (mntalloc.nrpcfree >= 10) {
1167                 kfree(r->rpc);
1168                 freetag(r->request.tag);
1169                 kfree(r);
1170         } else {
1171                 r->list = mntalloc.rpcfree;
1172                 mntalloc.rpcfree = r;
1173                 mntalloc.nrpcfree++;
1174         }
1175         mntalloc.nrpcused--;
1176         spin_unlock(&mntalloc.l);
1177 }
1178
1179 void mntqrm(struct mnt *m, struct mntrpc *r)
1180 {
1181         struct mntrpc **l, *f;
1182
1183         spin_lock(&m->lock);
1184         r->done = 1;
1185
1186         l = &m->queue;
1187         for (f = *l; f; f = f->list) {
1188                 if (f == r) {
1189                         *l = r->list;
1190                         break;
1191                 }
1192                 l = &f->list;
1193         }
1194         spin_unlock(&m->lock);
1195 }
1196
1197 struct mnt *mntchk(struct chan *c)
1198 {
1199         struct mnt *m;
1200
1201         /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1202
1203         if (c->mchan == NULL)
1204                 panic("mntchk 1: NULL mchan c %s\n", /*c2name(c) */ "channame?");
1205
1206         m = c->mchan->mux;
1207
1208         if (m == NULL)
1209                 printd("mntchk 2: NULL mux c %s c->mchan %s \n", c2name(c),
1210                            c2name(c->mchan));
1211
1212         /*
1213          * Was it closed and reused (was error(Eshutdown); now, it can't happen)
1214          */
1215         if (m->id == 0 || m->id >= c->dev)
1216                 panic("mntchk 3: can't happen");
1217
1218         return m;
1219 }
1220
1221 /*
1222  * Rewrite channel type and dev for in-flight data to
1223  * reflect local values.  These entries are known to be
1224  * the first two in the Dir encoding after the count.
1225  */
1226 void mntdirfix(uint8_t * dirbuf, struct chan *c)
1227 {
1228         /* TODO: We used to use the device's char (dc), instead of the type.  not
1229          * sure about the effects one way or the other.  This might be the type[2]
1230          * and dev[4] in a D (struct dir, see 9p's stat
1231          * (http://man.cat-v.org/plan_9/5/stat).  In which case, those should be for
1232          * the kernel's use.  Hopefully our kernel. */
1233         dirbuf += BIT16SZ;      /* skip count */
1234         PBIT16(dirbuf, c->type);
1235         dirbuf += BIT16SZ;
1236         PBIT32(dirbuf, c->dev);
1237 }
1238
1239 int rpcattn(void *v)
1240 {
1241         struct mntrpc *r;
1242
1243         r = v;
1244         return r->done || r->m->rip == 0;
1245 }
1246
1247 struct dev mntdevtab __devtab = {
1248         .name = "mnt",
1249
1250         .reset = devreset,
1251         .init = mntinit,
1252         .shutdown = devshutdown,
1253         .attach = mntattach,
1254         .walk = mntwalk,
1255         .stat = mntstat,
1256         .open = mntopen,
1257         .create = mntcreate,
1258         .close = mntclose,
1259         .read = mntread,
1260         .bread = devbread,
1261         .write = mntwrite,
1262         .bwrite = devbwrite,
1263         .remove = mntremove,
1264         .wstat = mntwstat,
1265         .power = devpower,
1266         .chaninfo = devchaninfo,
1267 };