devproc: change user from char* to struct username
[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                         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         /* TODO: this should use a qio helper directly.  qputback should have the
969          * qlocked, but I guess we assume we're the only one using it. */
970
971         /* hang the data off of the fcall struct */
972         l = &r->b;
973         *l = NULL;
974         do {
975                 b = qget(m->q);
976                 /* TODO: have better block helpers for this and the memmove below */
977                 b = linearizeblock(b);
978                 if (hlen > 0) {
979                         b->rp += hlen;
980                         len -= hlen;
981                         hlen = 0;
982                 }
983                 i = BLEN(b);
984                 if (i <= len) {
985                         len -= i;
986                         *l = b;
987                         l = &(b->next);
988                 } else {
989                         /* split block and put unused bit back */
990                         nb = block_alloc(i - len, MEM_WAIT);
991                         memmove(nb->wp, b->rp + len, i - len);
992                         b->wp = b->rp + len;
993                         nb->wp += i - len;
994                         qputback(m->q, nb);
995                         *l = b;
996                         return 0;
997                 }
998         } while (len > 0);
999
1000         return 0;
1001 }
1002
1003 void mntgate(struct mnt *m)
1004 {
1005         struct mntrpc *q;
1006
1007         spin_lock(&m->lock);
1008         m->rip = 0;
1009         for (q = m->queue; q; q = q->list) {
1010                 if (q->done == 0)
1011                         if (rendez_wakeup(&q->r))
1012                                 break;
1013         }
1014         spin_unlock(&m->lock);
1015 }
1016
1017 void mountmux(struct mnt *m, struct mntrpc *r)
1018 {
1019         struct mntrpc **l, *q;
1020
1021         spin_lock(&m->lock);
1022         l = &m->queue;
1023         for (q = *l; q; q = q->list) {
1024                 /* look for a reply to a message */
1025                 if (q->request.tag == r->reply.tag) {
1026                         *l = q->list;
1027                         if (q != r) {
1028                                 /*
1029                                  * Completed someone else.
1030                                  * Trade pointers to receive buffer.
1031                                  */
1032                                 q->reply = r->reply;
1033                                 q->b = r->b;
1034                                 r->b = NULL;
1035                         }
1036                         q->done = 1;
1037                         spin_unlock(&m->lock);
1038                         if (mntstats != NULL)
1039                                 (*mntstats) (q->request.type,
1040                                                          m->c, q->stime, q->reqlen + r->replen);
1041                         if (q != r)
1042                                 rendez_wakeup(&q->r);
1043                         return;
1044                 }
1045                 l = &q->list;
1046         }
1047         spin_unlock(&m->lock);
1048         if (r->reply.type == Rerror) {
1049                 printd("unexpected reply tag %u; type %d (error %q)\n", r->reply.tag,
1050                            r->reply.type, r->reply.ename);
1051         } else {
1052                 printd("unexpected reply tag %u; type %d\n", r->reply.tag,
1053                            r->reply.type);
1054         }
1055 }
1056
1057 /*
1058  * Create a new flush request and chain the previous
1059  * requests from it
1060  */
1061 struct mntrpc *mntflushalloc(struct mntrpc *r, uint32_t iounit)
1062 {
1063         struct mntrpc *fr;
1064
1065         fr = mntralloc(0, iounit);
1066
1067         fr->request.type = Tflush;
1068         if (r->request.type == Tflush)
1069                 fr->request.oldtag = r->request.oldtag;
1070         else
1071                 fr->request.oldtag = r->request.tag;
1072         fr->flushed = r;
1073
1074         return fr;
1075 }
1076
1077 /*
1078  *  Free a chain of flushes.  Remove each unanswered
1079  *  flush and the original message from the unanswered
1080  *  request queue.  Mark the original message as done
1081  *  and if it hasn't been answered set the reply to to
1082  *  Rflush.
1083  */
1084 void mntflushfree(struct mnt *m, struct mntrpc *r)
1085 {
1086         struct mntrpc *fr;
1087
1088         while (r) {
1089                 fr = r->flushed;
1090                 if (!r->done) {
1091                         r->reply.type = Rflush;
1092                         mntqrm(m, r);
1093                 }
1094                 if (fr)
1095                         mntfree(r);
1096                 r = fr;
1097         }
1098 }
1099
1100 static int alloctag(void)
1101 {
1102         return get_u16(mntalloc.tags);
1103 }
1104
1105 static void freetag(int t)
1106 {
1107         put_u16(mntalloc.tags, t);
1108 }
1109
1110 struct mntrpc *mntralloc(struct chan *c, uint32_t msize)
1111 {
1112         struct mntrpc *new;
1113
1114         spin_lock(&mntalloc.l);
1115         new = mntalloc.rpcfree;
1116         if (new == NULL) {
1117                 new = kzmalloc(sizeof(struct mntrpc), 0);
1118                 if (new == NULL) {
1119                         spin_unlock(&mntalloc.l);
1120                         exhausted("mount rpc header");
1121                 }
1122                 rendez_init(&new->r);
1123                 /*
1124                  * The header is split from the data buffer as
1125                  * mountmux may swap the buffer with another header.
1126                  */
1127                 new->rpc = kzmalloc(msize, MEM_WAIT);
1128                 if (new->rpc == NULL) {
1129                         kfree(new);
1130                         spin_unlock(&mntalloc.l);
1131                         exhausted("mount rpc buffer");
1132                 }
1133                 new->rpclen = msize;
1134                 new->request.tag = alloctag();
1135                 if (new->request.tag == NOTAG) {
1136                         kfree(new);
1137                         spin_unlock(&mntalloc.l);
1138                         exhausted("rpc tags");
1139                 }
1140         } else {
1141                 mntalloc.rpcfree = new->list;
1142                 mntalloc.nrpcfree--;
1143                 if (new->rpclen < msize) {
1144                         kfree(new->rpc);
1145                         new->rpc = kzmalloc(msize, MEM_WAIT);
1146                         if (new->rpc == NULL) {
1147                                 kfree(new);
1148                                 mntalloc.nrpcused--;
1149                                 spin_unlock(&mntalloc.l);
1150                                 exhausted("mount rpc buffer");
1151                         }
1152                         new->rpclen = msize;
1153                 }
1154         }
1155         mntalloc.nrpcused++;
1156         spin_unlock(&mntalloc.l);
1157         new->c = c;
1158         new->done = 0;
1159         new->flushed = NULL;
1160         new->b = NULL;
1161         return new;
1162 }
1163
1164 void mntfree(struct mntrpc *r)
1165 {
1166         if (r->b != NULL)
1167                 freeblist(r->b);
1168         spin_lock(&mntalloc.l);
1169         if (mntalloc.nrpcfree >= 10) {
1170                 kfree(r->rpc);
1171                 freetag(r->request.tag);
1172                 kfree(r);
1173         } else {
1174                 r->list = mntalloc.rpcfree;
1175                 mntalloc.rpcfree = r;
1176                 mntalloc.nrpcfree++;
1177         }
1178         mntalloc.nrpcused--;
1179         spin_unlock(&mntalloc.l);
1180 }
1181
1182 void mntqrm(struct mnt *m, struct mntrpc *r)
1183 {
1184         struct mntrpc **l, *f;
1185
1186         spin_lock(&m->lock);
1187         r->done = 1;
1188
1189         l = &m->queue;
1190         for (f = *l; f; f = f->list) {
1191                 if (f == r) {
1192                         *l = r->list;
1193                         break;
1194                 }
1195                 l = &f->list;
1196         }
1197         spin_unlock(&m->lock);
1198 }
1199
1200 struct mnt *mntchk(struct chan *c)
1201 {
1202         struct mnt *m;
1203
1204         /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1205
1206         if (c->mchan == NULL)
1207                 panic("mntchk 1: NULL mchan c %s\n", /*c2name(c) */ "channame?");
1208
1209         m = c->mchan->mux;
1210
1211         if (m == NULL)
1212                 printd("mntchk 2: NULL mux c %s c->mchan %s \n", c2name(c),
1213                            c2name(c->mchan));
1214
1215         /*
1216          * Was it closed and reused (was error(Eshutdown); now, it can't happen)
1217          */
1218         if (m->id == 0 || m->id >= c->dev)
1219                 panic("mntchk 3: can't happen");
1220
1221         return m;
1222 }
1223
1224 /*
1225  * Rewrite channel type and dev for in-flight data to
1226  * reflect local values.  These entries are known to be
1227  * the first two in the Dir encoding after the count.
1228  */
1229 void mntdirfix(uint8_t * dirbuf, struct chan *c)
1230 {
1231         /* TODO: We used to use the device's char (dc), instead of the type.  not
1232          * sure about the effects one way or the other.  This might be the type[2]
1233          * and dev[4] in a D (struct dir, see 9p's stat
1234          * (http://man.cat-v.org/plan_9/5/stat).  In which case, those should be for
1235          * the kernel's use.  Hopefully our kernel. */
1236         dirbuf += BIT16SZ;      /* skip count */
1237         PBIT16(dirbuf, c->type);
1238         dirbuf += BIT16SZ;
1239         PBIT32(dirbuf, c->dev);
1240 }
1241
1242 int rpcattn(void *v)
1243 {
1244         struct mntrpc *r;
1245
1246         r = v;
1247         return r->done || r->m->rip == 0;
1248 }
1249
1250 struct dev mntdevtab __devtab = {
1251         .name = "mnt",
1252
1253         .reset = devreset,
1254         .init = mntinit,
1255         .shutdown = devshutdown,
1256         .attach = mntattach,
1257         .walk = mntwalk,
1258         .stat = mntstat,
1259         .open = mntopen,
1260         .create = mntcreate,
1261         .close = mntclose,
1262         .read = mntread,
1263         .bread = devbread,
1264         .write = mntwrite,
1265         .bwrite = devbwrite,
1266         .remove = mntremove,
1267         .wstat = mntwstat,
1268         .power = devpower,
1269         .chaninfo = devchaninfo,
1270 };