Add the Inferno license to files we got from Inferno
[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                 strncpy(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, NULL);
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, NULL);
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, NULL);
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, NULL);
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, NULL);
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, NULL);
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, NULL);
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, NULL);
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, NULL);
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         "mnt",
1249
1250         devreset,
1251         mntinit,
1252         devshutdown,
1253         mntattach,
1254         mntwalk,
1255         mntstat,
1256         mntopen,
1257         mntcreate,
1258         mntclose,
1259         mntread,
1260         devbread,
1261         mntwrite,
1262         devbwrite,
1263         mntremove,
1264         mntwstat,
1265         devpower,
1266         devchaninfo,
1267 };