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 Mntrpc* flushed; /* message this one flushes */
33 void *iocomarg; /* Rpc completion callback for pipelining */
34 void (*iocomfun)(void*, int);
35 char done; /* Rpc completed */
40 TAGSHIFT = 5, /* ulong has to be 32 bits */
41 TAGMASK = (1<<TAGSHIFT)-1,
42 NMASK = (64*1024)>>TAGSHIFT,
45 static struct Mntalloc
48 Mnt* list; /* Mount devices in use */
49 Mnt* mntfree; /* Free list */
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*);
73 char Esbadstat[] = "invalid directory entry received from server";
74 char Enoversion[] = "version not established for mount channel";
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] */
91 * Version is not multiplexed: message sent only once per connection.
94 mntversion(Chan *c, char *version, int msize, int returnlen)
105 eqlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
107 qunlock(&c->umqlock);
114 if(msize > c->iounit && c->iounit != 0)
117 if(v == nil || v[0] == '\0')
122 error("bad iounit in version call");
123 if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
124 error("bad 9P version specification");
129 qunlock(&c->umqlock);
132 strecpy(buf, buf+sizeof buf, m->version);
134 if(strncmp(buf, v, k) != 0){
135 snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
141 memmove(version, buf, k);
150 msg = malloc(8192+IOHDRSZ);
152 exhausted("version memory");
157 k = convS2M(&f, msg, 8192+IOHDRSZ);
159 error("bad fversion conversion on send");
166 l = devtab[c->type]->write(c, msg, k, oo);
172 error("short write in fversion");
175 /* message sent; receive and decode reply */
176 k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
178 error("EOF receiving fversion reply");
184 l = convM2S(msg, k, &f);
186 error("bad fversion conversion on reply");
187 if(f.type != Rversion){
190 error("unexpected reply type in fversion");
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)
203 kstrdup(&v, f.version);
204 q = qopen(10*MAXRPC, 0, nil, nil);
207 exhausted("mount queues");
210 /* now build Mnt associated with this connection */
212 m = mntalloc.mntfree;
214 mntalloc.mntfree = m->list;
217 m = malloc(sizeof(Mnt));
221 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)
262 mntversion(c, VERSION9P, MAXRPC, 0);
270 /* Close must not be called since it will
271 * call mnt recursively
283 r->request.type = Tauth;
284 r->request.afid = c->fid;
285 r->request.uname = up->user;
286 r->request.aname = spec;
289 c->qid = r->reply.aqid;
294 c->iounit = m->msize-IOHDRSZ;
306 mntattach(char *muxattach)
318 bogus = *((struct bogus *)muxattach);
323 mntversion(c, nil, 0, 0);
331 /* Close must not be called since it will
332 * call mnt recursively
343 r->request.type = Tattach;
344 r->request.fid = c->fid;
345 if(bogus.authchan == nil)
346 r->request.afid = NOFID;
348 r->request.afid = bogus.authchan->fid;
349 r->request.uname = up->user;
350 r->request.aname = bogus.spec;
353 c->qid = r->reply.qid;
363 if(bogus.flags&MCACHE)
373 c = devattach('M', 0);
375 c->dev = mntalloc.id++;
379 panic("mntchan non-zero %p", c->mchan);
384 mntwalk(Chan *c, Chan *nc, char **name, int nname)
392 print("mntwalk: nc != nil\n");
394 error("devmnt: too many name elements");
396 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
398 if(alloc && wq->clone!=nil)
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.
414 nc->flag |= (c->flag & CCACHE);
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*));
431 if(r->reply.nwqid > nname)
432 error("too many QIDs returned by walk");
433 if(r->reply.nwqid < nname){
437 if(r->reply.nwqid == 0){
444 /* move new fid onto mnt device and update its qid */
445 if(wq->clone != nil){
447 wq->clone->type = c->type;
448 wq->clone->mchan = c->mchan;
451 if(r->reply.nwqid > 0)
452 wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
454 wq->nqid = r->reply.nwqid;
455 for(i=0; i<wq->nqid; i++)
456 wq->qid[i] = r->reply.wqid[i];
466 mntstat(Chan *c, uchar *dp, int n)
479 r->request.type = Tstat;
480 r->request.fid = c->fid;
483 if(r->reply.nstat > n){
485 PBIT16((uchar*)dp, r->reply.nstat-2);
488 memmove(dp, r->reply.stat, n);
498 mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
509 r->request.type = type;
510 r->request.fid = c->fid;
511 r->request.mode = omode;
513 r->request.perm = perm;
514 r->request.name = name;
518 c->qid = r->reply.qid;
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;
535 mntopen(Chan *c, int omode)
537 return mntopencreate(Topen, c, nil, omode, 0);
541 mntcreate(Chan *c, char *name, int omode, ulong perm)
543 return mntopencreate(Tcreate, c, name, omode, perm);
547 mntclunk(Chan *c, int t)
560 r->request.fid = c->fid;
572 while((r = m->queue) != nil){
584 for(f = *l; f != nil; f = f->list) {
591 m->list = mntalloc.mntfree;
592 mntalloc.mntfree = m;
605 mntclunk(c, Tremove);
609 mntwstat(Chan *c, uchar *dp, int n)
620 r->request.type = Twstat;
621 r->request.fid = c->fid;
622 r->request.nstat = n;
623 r->request.stat = dp;
631 mntread(Chan *c, void *buf, long n, vlong off)
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);
643 validstat(p, dirlen);
653 mntwrite(Chan *c, void *buf, long n, vlong off)
655 return mntrdwr(Twrite, c, buf, n, off);
667 if((c->flag & CCACHE) == 0 || c->mcp == nil)
669 off = r->request.offset;
670 switch(r->reply.type){
673 if(m > r->request.count)
674 m = r->request.count;
676 for(b = r->b; m > 0 && b != nil; b = b->next) {
680 cupdate(c, b->rp, n, off);
685 if(convM2S(r->rpc, r->rpclen, &r->request) == 0)
687 cwrite(c, (uchar*)r->request.data, r->request.count, off);
693 mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
709 if(type == Tread && (c->flag&CCACHE) != 0) {
710 nr = cread(c, (uchar*)uba, nreq, off);
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;
733 r->b = bl2mem((uchar*)uba, r->b, nr);
742 if(nr != nreq || n == 0 || up->nnote)
767 tsleep(p, mntprocwork, p, 500);
791 mntdefer(void (*f)(Mntrpc*, void*), Mntrpc *r, void *a)
799 for(i = 0; i < nelem(m->defered); i++){
813 kproc("mntporc", mntproc, p);
825 rahproc(Mntrpc *r, void *a)
845 rahfindrpc(Mntrah *rah, vlong off)
851 for(i=0; i<nelem(rah->r); i++){
852 if((r = rah->r[i]) == nil)
854 n = r->request.count;
855 o = r->request.offset;
856 if(off >= o && off < o+n)
863 mntrahinit(Mntrah *rah)
871 for(i=0; i<nelem(rah->r); i++){
872 if((r = rah->r[i]) != nil){
874 sleep(rah, rahdone, r);
888 mntrahread(Mntrah *rah, Chan *c, uchar *buf, long len, vlong off)
898 if(rahfindrpc(rah, off) == nil)
903 if(rah->seq >= 2*c->iounit){
904 w = (off / c->iounit) * c->iounit;
906 for(o = w; w < e; o += c->iounit){
907 if(rahfindrpc(rah, o) != nil)
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))
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)){
933 while(len > 0 && (r = rahfindrpc(rah, off)) != nil){
935 sleep(rah, rahdone, r);
937 switch(r->reply.type){
943 error(r->reply.ename);
948 n = r->request.count;
949 o = r->request.offset;
950 if(r->reply.count < n)
957 n = readblist(r->b, buf, n, off - o);
972 mountrpc(Mnt *m, Mntrpc *r)
977 r->reply.type = Tmax; /* can't ever be a valid message type */
984 error(r->reply.ename);
988 if(t == r->request.type+1)
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);
999 mountio(Mnt *m, Mntrpc *r)
1006 if(strcmp(up->errstr, Eintr) != 0 || waserror()){
1007 r = mntflushfree(m, r);
1008 switch(r->request.type){
1011 /* botch, abandon fid */
1012 if(strcmp(up->errstr, Ehungup) != 0)
1017 r = mntflushalloc(r);
1024 r->iocomarg = up->iocomarg;
1025 r->iocomfun = up->iocomfun;
1031 /* Transmit a file system rpc */
1032 n = sizeS2M(&r->request);
1035 r->rpc = mallocz(((uint)n+127) & ~127, 0);
1038 exhausted("mount rpc buffer");
1040 r->rpclen = msize(r->rpc);
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);
1048 if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
1052 if(r->iocomfun != nil)
1053 (*r->iocomfun)(r->iocomarg, 0);
1055 /* Gate readers onto the mount point one at a time */
1061 sleep(r->z, rpcattn, r);
1070 while(r->done == 0) {
1071 if(mntrpcread(m, r) < 0)
1081 doread(Mnt *m, int len)
1085 while(qlen(m->q) < len){
1086 b = devtab[m->c->type]->bread(m->c, m->msize, 0);
1089 if(blocklen(b) == 0){
1099 mntrpcread(Mnt *m, Mntrpc *r)
1101 int i, t, len, hlen;
1107 /* read at least length, type, and tag and pullup to a single block */
1108 if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
1110 nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
1112 /* read in the rest of the message, avoid ridiculous (for now) message sizes */
1113 len = GBIT32(nb->rp);
1115 qdiscard(m->q, qlen(m->q));
1118 if(doread(m, len) < 0)
1121 /* pullup the header (i.e. everything except data) */
1122 t = nb->rp[BIT32SZ];
1125 hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
1131 nb = pullupqueue(m->q, hlen);
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);
1140 /* hang the data off of the fcall struct */
1156 /* split block and put unused bit back */
1158 memmove(nb->wp, b->rp+len, i-len);
1177 for(q = m->queue; q != nil; q = q->list) {
1186 mountmux(Mnt *m, Mntrpc *r)
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) {
1199 if(q->iocomfun != nil)
1200 (*q->iocomfun)(q->iocomarg, 1);
1208 * Completed someone else.
1209 * Trade pointers to receive buffer.
1211 q->reply = r->reply;
1224 print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
1228 * Create a new flush request and chain the previous
1232 mntflushalloc(Mntrpc *r)
1236 fr = mntralloc(r->c);
1237 fr->request.type = Tflush;
1238 if(r->request.type == Tflush)
1239 fr->request.oldtag = r->request.oldtag;
1241 fr->request.oldtag = r->request.tag;
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.
1255 mntflushfree(Mnt *m, Mntrpc *r)
1262 r->reply.type = Rflush;
1279 for(i = 0; i < NMASK; i++){
1280 v = mntalloc.tagmask[i];
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;
1289 panic("no friggin tags left");
1296 mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1304 if(mntalloc.nrpcfree == 0) {
1306 new = malloc(sizeof(Mntrpc));
1308 exhausted("mount rpc header");
1312 new->request.tag = alloctag();
1315 new = mntalloc.rpcfree;
1320 mntalloc.rpcfree = new->list;
1321 mntalloc.nrpcfree--;
1323 mntalloc.nrpcused++;
1337 mntalloc.nrpcused--;
1338 if(mntalloc.nrpcfree < 32) {
1339 r->list = mntalloc.rpcfree;
1340 mntalloc.rpcfree = r;
1341 mntalloc.nrpcfree++;
1345 freetag(r->request.tag);
1352 mntqrm(Mnt *m, Mntrpc *r)
1360 for(f = *l; f != nil; f = f->list) {
1375 /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1377 panic("mntchk 1: nil mchan c %s", chanpath(c));
1381 print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
1384 * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
1386 if(m->id == 0 || m->id >= c->dev)
1387 panic("mntchk 3: can't happen");
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.
1398 mntdirfix(uchar *dirbuf, Chan *c)
1402 r = devtab[c->type]->dc;
1403 dirbuf += BIT16SZ; /* skip count */
1406 PBIT32(dirbuf, c->dev);
1415 return r->done || r->m->rip == nil;