2 #include "../port/lib.h"
6 #include "../port/error.h"
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
19 #define MAXRPC (IOHDRSZ+8192)
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 uvlong stime; /* start time for mnt statistics */
33 ulong reqlen; /* request length for mnt statistics */
34 ulong replen; /* reply length for mnt statistics */
35 Mntrpc* flushed; /* message this one flushes */
36 char done; /* Rpc completed */
41 TAGSHIFT = 5, /* ulong has to be 32 bits */
42 TAGMASK = (1<<TAGSHIFT)-1,
43 NMASK = (64*1024)>>TAGSHIFT,
49 Mnt* list; /* Mount devices in use */
50 Mnt* mntfree; /* Free list */
59 void mntdirfix(uchar*, Chan*);
60 Mntrpc* mntflushalloc(Mntrpc*, ulong);
61 Mntrpc* mntflushfree(Mnt*, Mntrpc*);
62 void mntfree(Mntrpc*);
64 void mntqrm(Mnt*, Mntrpc*);
65 Mntrpc* mntralloc(Chan*, ulong);
66 long mntrdwr(int, Chan*, void*, long, vlong);
67 int mntrpcread(Mnt*, Mntrpc*);
68 void mountio(Mnt*, Mntrpc*);
69 void mountmux(Mnt*, Mntrpc*);
70 void mountrpc(Mnt*, Mntrpc*);
74 char Esbadstat[] = "invalid directory entry received from server";
75 char Enoversion[] = "version not established for mount channel";
82 mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */
83 mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */
84 fmtinstall('F', fcallfmt);
85 fmtinstall('D', dirfmt);
86 /* We can't install %M since eipfmt does and is used in the kernel [sape] */
92 * Version is not multiplexed: message sent only once per connection.
95 mntversion(Chan *c, char *version, int msize, int returnlen)
106 eqlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
108 qunlock(&c->umqlock);
115 if(msize > c->iounit && c->iounit != 0)
118 if(v == nil || v[0] == '\0')
123 error("bad iounit in version call");
124 if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
125 error("bad 9P version specification");
130 qunlock(&c->umqlock);
133 strecpy(buf, buf+sizeof buf, m->version);
135 if(strncmp(buf, v, k) != 0){
136 snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
142 memmove(version, buf, k);
151 msg = malloc(8192+IOHDRSZ);
153 exhausted("version memory");
158 k = convS2M(&f, msg, 8192+IOHDRSZ);
160 error("bad fversion conversion on send");
167 l = devtab[c->type]->write(c, msg, k, oo);
173 error("short write in fversion");
176 /* message sent; receive and decode reply */
177 k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
179 error("EOF receiving fversion reply");
185 l = convM2S(msg, k, &f);
187 error("bad fversion conversion on reply");
188 if(f.type != Rversion){
191 error("unexpected reply type in fversion");
194 error("server tries to increase msize in fversion");
195 if(f.msize<256 || f.msize>1024*1024)
196 error("nonsense value of msize in fversion");
197 k = strlen(f.version);
198 if(strncmp(f.version, v, k) != 0)
199 error("bad 9P version returned from server");
200 if(returnlen > 0 && returnlen < k)
204 kstrdup(&v, f.version);
205 q = qopen(10*MAXRPC, 0, nil, nil);
208 exhausted("mount queues");
211 /* now build Mnt associated with this connection */
213 m = mntalloc.mntfree;
215 mntalloc.mntfree = m->list;
217 m = malloc(sizeof(Mnt));
222 exhausted("mount devices");
225 m->list = mntalloc.list;
228 m->id = mntalloc.id++;
234 memmove(version, f.version, k); /* length was checked above */
236 poperror(); /* msg */
249 qunlock(&c->umqlock);
255 mntauth(Chan *c, char *spec)
263 mntversion(c, VERSION9P, MAXRPC, 0);
271 /* Close must not be called since it will
272 * call mnt recursively
278 r = mntralloc(0, m->msize);
285 r->request.type = Tauth;
286 r->request.afid = c->fid;
287 r->request.uname = up->user;
288 r->request.aname = spec;
291 c->qid = r->reply.aqid;
307 mntattach(char *muxattach)
319 bogus = *((struct bogus *)muxattach);
325 mntversion(c, nil, 0, 0);
333 /* Close must not be called since it will
334 * call mnt recursively
340 r = mntralloc(0, m->msize);
347 r->request.type = Tattach;
348 r->request.fid = c->fid;
349 if(bogus.authchan == nil)
350 r->request.afid = NOFID;
352 r->request.afid = bogus.authchan->fid;
353 r->request.uname = up->user;
354 r->request.aname = bogus.spec;
357 c->qid = r->reply.qid;
367 if(bogus.flags&MCACHE)
377 c = devattach('M', 0);
379 c->dev = mntalloc.id++;
383 panic("mntchan non-zero %p", c->mchan);
388 mntwalk(Chan *c, Chan *nc, char **name, int nname)
396 print("mntwalk: nc != nil\n");
398 error("devmnt: too many name elements");
400 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
402 if(alloc && wq->clone!=nil)
410 r = mntralloc(c, m->msize);
414 * Until the other side accepts this fid, we can't mntclose it.
415 * Therefore set type to 0 for now; rootclose is known to be safe.
418 nc->flag |= (c->flag & CCACHE);
427 r->request.type = Twalk;
428 r->request.fid = c->fid;
429 r->request.newfid = nc->fid;
430 r->request.nwname = nname;
431 memmove(r->request.wname, name, nname*sizeof(char*));
435 if(r->reply.nwqid > nname)
436 error("too many QIDs returned by walk");
437 if(r->reply.nwqid < nname){
441 if(r->reply.nwqid == 0){
448 /* move new fid onto mnt device and update its qid */
449 if(wq->clone != nil){
451 wq->clone->type = c->type;
452 wq->clone->mchan = c->mchan;
455 if(r->reply.nwqid > 0)
456 wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
458 wq->nqid = r->reply.nwqid;
459 for(i=0; i<wq->nqid; i++)
460 wq->qid[i] = r->reply.wqid[i];
470 mntstat(Chan *c, uchar *dp, int n)
478 r = mntralloc(c, m->msize);
483 r->request.type = Tstat;
484 r->request.fid = c->fid;
487 if(r->reply.nstat > n){
489 PBIT16((uchar*)dp, r->reply.nstat-2);
492 memmove(dp, r->reply.stat, n);
502 mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
508 r = mntralloc(c, m->msize);
513 r->request.type = type;
514 r->request.fid = c->fid;
515 r->request.mode = omode;
517 r->request.perm = perm;
518 r->request.name = name;
522 c->qid = r->reply.qid;
524 c->mode = openmode(omode);
525 c->iounit = r->reply.iounit;
526 if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
527 c->iounit = m->msize-IOHDRSZ;
539 mntopen(Chan *c, int omode)
541 return mntopencreate(Topen, c, nil, omode, 0);
545 mntcreate(Chan *c, char *name, int omode, ulong perm)
547 return mntopencreate(Tcreate, c, name, omode, perm);
551 mntclunk(Chan *c, int t)
557 r = mntralloc(c, m->msize);
564 r->request.fid = c->fid;
576 while((r = m->queue) != nil){
588 for(f = *l; f != nil; f = f->list) {
595 m->list = mntalloc.mntfree;
596 mntalloc.mntfree = m;
609 mntclunk(c, Tremove);
613 mntwstat(Chan *c, uchar *dp, int n)
619 r = mntralloc(c, m->msize);
624 r->request.type = Twstat;
625 r->request.fid = c->fid;
626 r->request.nstat = n;
627 r->request.stat = dp;
635 mntread(Chan *c, void *buf, long n, vlong off)
638 int nc, cache, isdir, dirlen;
641 cache = c->flag & CCACHE;
642 if(c->qid.type & QTDIR) {
649 nc = cread(c, buf, n, off);
657 n = mntrdwr(Tread, c, p, n, off);
658 cupdate(c, p, n, off);
662 n = mntrdwr(Tread, c, buf, n, off);
664 for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
665 dirlen = BIT16SZ+GBIT16(p);
668 validstat(p, dirlen);
678 mntwrite(Chan *c, void *buf, long n, vlong off)
680 return mntrdwr(Twrite, c, buf, n, off);
684 mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
695 cache = c->flag & CCACHE;
696 if(c->qid.type & QTDIR)
699 r = mntralloc(c, m->msize);
704 r->request.type = type;
705 r->request.fid = c->fid;
706 r->request.offset = off;
707 r->request.data = uba;
709 if(nr > m->msize-IOHDRSZ)
710 nr = m->msize-IOHDRSZ;
711 r->request.count = nr;
713 nreq = r->request.count;
719 r->b = bl2mem((uchar*)uba, r->b, nr);
721 cwrite(c, (uchar*)uba, nr, off);
729 if(nr != nreq || n == 0 || up->nnote)
736 mountrpc(Mnt *m, Mntrpc *r)
742 r->reply.type = Tmax; /* can't ever be a valid message type */
749 error(r->reply.ename);
753 if(t == r->request.type+1)
756 if(m->c->path != nil)
759 if(r->c != nil && r->c->path != nil)
761 print("mnt: proc %s %lud: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
762 up->text, up->pid, sn, cn,
763 r, r->request.tag, r->request.fid, r->request.type,
764 r->reply.type, r->reply.tag);
770 mountio(Mnt *m, Mntrpc *r)
777 if(strcmp(up->errstr, Eintr) != 0){
778 r = mntflushfree(m, r);
779 switch(r->request.type){
782 /* botch, abandon fid */
783 if(strcmp(up->errstr, Ehungup) != 0)
788 r = mntflushalloc(r, m->msize);
798 /* Transmit a file system rpc */
801 n = convS2M(&r->request, r->rpc, m->msize);
803 print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
804 up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
808 if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
810 r->stime = fastticks(nil);
813 /* Gate readers onto the mount point one at a time */
819 sleep(r->z, rpcattn, r);
828 while(r->done == 0) {
829 if(mntrpcread(m, r) < 0)
839 doread(Mnt *m, int len)
843 while(qlen(m->q) < len){
844 b = devtab[m->c->type]->bread(m->c, m->msize, 0);
847 if(blocklen(b) == 0){
857 mntrpcread(Mnt *m, Mntrpc *r)
865 /* read at least length, type, and tag and pullup to a single block */
866 if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
868 nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
870 /* read in the rest of the message, avoid ridiculous (for now) message sizes */
871 len = GBIT32(nb->rp);
873 qdiscard(m->q, qlen(m->q));
876 if(doread(m, len) < 0)
879 /* pullup the header (i.e. everything except data) */
883 hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
889 nb = pullupqueue(m->q, hlen);
891 if(convM2S(nb->rp, len, &r->reply) <= 0){
892 /* bad message, dump it */
893 print("mntrpcread: convM2S failed\n");
898 /* hang the data off of the fcall struct */
914 /* split block and put unused bit back */
916 memmove(nb->wp, b->rp+len, i-len);
935 for(q = m->queue; q != nil; q = q->list) {
944 mountmux(Mnt *m, Mntrpc *r)
951 for(q = *l; q != nil; q = q->list) {
952 /* look for a reply to a message */
953 if(q->request.tag == r->reply.tag) {
961 * Completed someone else.
962 * Trade pointers to receive buffer.
977 print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
981 * Create a new flush request and chain the previous
985 mntflushalloc(Mntrpc *r, ulong iounit)
989 fr = mntralloc(0, iounit);
991 fr->request.type = Tflush;
992 if(r->request.type == Tflush)
993 fr->request.oldtag = r->request.oldtag;
995 fr->request.oldtag = r->request.tag;
1002 * Free a chain of flushes. Remove each unanswered
1003 * flush and the original message from the unanswered
1004 * request queue. Mark the original message as done
1005 * and if it hasn't been answered set the reply to to
1006 * Rflush. Return the original rpc.
1009 mntflushfree(Mnt *m, Mntrpc *r)
1016 r->reply.type = Rflush;
1033 for(i = 0; i < NMASK; i++){
1034 v = mntalloc.tagmask[i];
1037 for(j = 0; j < 1<<TAGSHIFT; j++)
1038 if((v & (1<<j)) == 0){
1039 mntalloc.tagmask[i] |= 1<<j;
1040 return (i<<TAGSHIFT) + j;
1043 panic("no friggin tags left");
1050 mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1054 mntralloc(Chan *c, ulong msize)
1059 new = mntalloc.rpcfree;
1061 new = malloc(sizeof(Mntrpc));
1064 exhausted("mount rpc header");
1067 * The header is split from the data buffer as
1068 * mountmux may swap the buffer with another header.
1070 new->rpc = mallocz(msize, 0);
1071 if(new->rpc == nil){
1074 exhausted("mount rpc buffer");
1076 new->rpclen = msize;
1077 new->request.tag = alloctag();
1080 mntalloc.rpcfree = new->list;
1081 mntalloc.nrpcfree--;
1082 if(new->rpclen < msize){
1084 new->rpc = mallocz(msize, 0);
1085 if(new->rpc == nil){
1087 mntalloc.nrpcused--;
1089 exhausted("mount rpc buffer");
1091 new->rpclen = msize;
1094 mntalloc.nrpcused++;
1109 if(mntalloc.nrpcfree >= 10){
1111 freetag(r->request.tag);
1115 r->list = mntalloc.rpcfree;
1116 mntalloc.rpcfree = r;
1117 mntalloc.nrpcfree++;
1119 mntalloc.nrpcused--;
1124 mntqrm(Mnt *m, Mntrpc *r)
1132 for(f = *l; f != nil; f = f->list) {
1147 /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1150 panic("mntchk 1: nil mchan c %s", chanpath(c));
1155 print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
1158 * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
1160 if(m->id == 0 || m->id >= c->dev)
1161 panic("mntchk 3: can't happen");
1167 * Rewrite channel type and dev for in-flight data to
1168 * reflect local values. These entries are known to be
1169 * the first two in the Dir encoding after the count.
1172 mntdirfix(uchar *dirbuf, Chan *c)
1176 r = devtab[c->type]->dc;
1177 dirbuf += BIT16SZ; /* skip count */
1180 PBIT32(dirbuf, c->dev);
1189 return r->done || r->m->rip == nil;