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