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