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