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