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);
171 error("short write in fversion");
174 /* message sent; receive and decode reply */
175 for(k = 0; k < BIT32SZ || (k < GBIT32(msg) && k < 8192+IOHDRSZ); k += l){
176 l = devtab[c->type]->read(c, msg+k, 8192+IOHDRSZ-k, 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(Chan *c, Chan *ac, char *spec, int flags)
313 mntversion(c, nil, 0, 0);
321 /* Close must not be called since it will
322 * call mnt recursively
333 r->request.type = Tattach;
334 r->request.fid = c->fid;
336 r->request.afid = NOFID;
338 r->request.afid = ac->fid;
339 r->request.uname = up->user;
340 r->request.aname = spec;
343 c->qid = r->reply.qid;
370 c = devattach('M', 0);
372 c->dev = mntalloc.id++;
376 panic("mntchan non-zero %p", c->mchan);
381 mntwalk(Chan *c, Chan *nc, char **name, int nname)
389 print("mntwalk: nc != nil\n");
391 error("devmnt: too many name elements");
393 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
395 if(alloc && wq->clone!=nil)
407 * Until the other side accepts this fid, we can't mntclose it.
408 * Therefore set type to 0 for now; rootclose is known to be safe.
411 nc->flag |= (c->flag & CCACHE);
420 r->request.type = Twalk;
421 r->request.fid = c->fid;
422 r->request.newfid = nc->fid;
423 r->request.nwname = nname;
424 memmove(r->request.wname, name, nname*sizeof(char*));
428 if(r->reply.nwqid > nname)
429 error("too many QIDs returned by walk");
430 if(r->reply.nwqid < nname){
434 if(r->reply.nwqid == 0){
441 /* move new fid onto mnt device and update its qid */
442 if(wq->clone != nil){
444 wq->clone->type = c->type;
445 wq->clone->mchan = c->mchan;
448 if(r->reply.nwqid > 0)
449 wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
451 wq->nqid = r->reply.nwqid;
452 for(i=0; i<wq->nqid; i++)
453 wq->qid[i] = r->reply.wqid[i];
463 mntstat(Chan *c, uchar *dp, int n)
476 r->request.type = Tstat;
477 r->request.fid = c->fid;
480 if(r->reply.nstat > n){
482 PBIT16((uchar*)dp, r->reply.nstat-2);
485 memmove(dp, r->reply.stat, n);
495 mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
506 r->request.type = type;
507 r->request.fid = c->fid;
508 r->request.mode = omode;
510 r->request.perm = perm;
511 r->request.name = name;
515 c->qid = r->reply.qid;
517 c->mode = openmode(omode);
518 c->iounit = r->reply.iounit;
519 if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
520 c->iounit = m->msize-IOHDRSZ;
532 mntopen(Chan *c, int omode)
534 return mntopencreate(Topen, c, nil, omode, 0);
538 mntcreate(Chan *c, char *name, int omode, ulong perm)
540 return mntopencreate(Tcreate, c, name, omode, perm);
544 mntclunk(Chan *c, int t)
557 r->request.fid = c->fid;
569 while((r = m->queue) != nil){
581 for(f = *l; f != nil; f = f->list) {
588 m->list = mntalloc.mntfree;
589 mntalloc.mntfree = m;
602 mntclunk(c, Tremove);
606 mntwstat(Chan *c, uchar *dp, int n)
617 r->request.type = Twstat;
618 r->request.fid = c->fid;
619 r->request.nstat = n;
620 r->request.stat = dp;
628 mntread(Chan *c, void *buf, long n, vlong off)
634 n = mntrdwr(Tread, c, p, n, off);
635 if(c->qid.type & QTDIR) {
636 for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
637 dirlen = BIT16SZ+GBIT16(p);
640 validstat(p, dirlen);
650 mntwrite(Chan *c, void *buf, long n, vlong off)
652 return mntrdwr(Twrite, c, buf, n, off);
664 if((c->flag & CCACHE) == 0 || c->mcp == nil)
666 off = r->request.offset;
667 switch(r->reply.type){
670 if(m > r->request.count)
671 m = r->request.count;
672 for(b = r->b; m > 0 && b != nil; m -= n, b = b->next) {
676 cupdate(c, b->rp, n, off);
681 if(convM2S(r->rpc, r->rpclen, &r->request) == 0)
683 cwrite(c, (uchar*)r->request.data, r->request.count, off);
689 mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
705 if(type == Tread && (c->flag&CCACHE) != 0) {
706 nr = cread(c, (uchar*)uba, nreq, off);
718 r->request.type = type;
719 r->request.fid = c->fid;
720 r->request.offset = off;
721 r->request.data = uba;
722 r->request.count = nreq;
729 r->b = bl2mem((uchar*)uba, r->b, nr);
738 if(nr != nreq || n == 0 || up->nnote)
763 tsleep(p, mntprocwork, p, 500);
787 mntdefer(void (*f)(Mntrpc*, void*), Mntrpc *r, void *a)
795 for(i = 0; i < nelem(m->defered); i++){
809 kproc("mntproc", mntproc, p);
821 rahproc(Mntrpc *r, void *a)
841 rahfindrpc(Mntrah *rah, vlong off)
847 for(i=0; i<nelem(rah->r); i++){
848 if((r = rah->r[i]) == nil)
850 n = r->request.count;
851 o = r->request.offset;
852 if(off >= o && off < o+n)
859 mntrahinit(Mntrah *rah)
867 for(i=0; i<nelem(rah->r); i++){
868 if((r = rah->r[i]) != nil){
870 sleep(rah, rahdone, r);
884 mntrahread(Mntrah *rah, Chan *c, uchar *buf, long len, vlong off)
894 if(rahfindrpc(rah, off) == nil)
899 if(rah->seq >= 2*c->iounit){
900 w = (off / c->iounit) * c->iounit;
902 for(o = w; w < e; o += c->iounit){
903 if(rahfindrpc(rah, o) != nil)
906 rr = &rah->r[rah->i % nelem(rah->r)];
907 if((r = *rr) != nil){
908 if(!rahdone(r) || (r->request.offset >= w && r->request.offset < e))
915 r->request.type = Tread;
916 r->request.fid = c->fid;
917 r->request.offset = o;
918 r->request.count = c->iounit;
919 if(!mntdefer(rahproc, r, rah)){
929 while(len > 0 && (r = rahfindrpc(rah, off)) != nil){
931 sleep(rah, rahdone, r);
933 switch(r->reply.type){
939 error(r->reply.ename);
944 n = r->request.count;
945 o = r->request.offset;
946 if(r->reply.count < n)
953 n = readblist(r->b, buf, n, off - o);
968 mountrpc(Mnt *m, Mntrpc *r)
973 r->reply.type = Tmax; /* can't ever be a valid message type */
980 error(r->reply.ename);
984 if(t == r->request.type+1)
986 print("mnt: proc %s %lud: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
987 up->text, up->pid, chanpath(m->c), chanpath(r->c),
988 r, r->request.tag, r->request.fid, r->request.type,
989 r->reply.type, r->reply.tag);
995 mountio(Mnt *m, Mntrpc *r)
1002 if(strcmp(up->errstr, Eintr) != 0 || waserror()){
1003 r = mntflushfree(m, r);
1004 switch(r->request.type){
1007 /* botch, abandon fid */
1008 if(strcmp(up->errstr, Ehungup) != 0)
1013 r = mntflushalloc(r);
1020 r->iocomarg = up->iocomarg;
1021 r->iocomfun = up->iocomfun;
1027 /* Transmit a file system rpc */
1028 n = sizeS2M(&r->request);
1031 r->rpc = mallocz(((uint)n+127) & ~127, 0);
1034 exhausted("mount rpc buffer");
1036 r->rpclen = msize(r->rpc);
1038 n = convS2M(&r->request, r->rpc, r->rpclen);
1039 if(n <= 0 || n > m->msize) {
1040 print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
1041 up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
1044 if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
1048 if(r->iocomfun != nil)
1049 (*r->iocomfun)(r->iocomarg, 0);
1051 /* Gate readers onto the mount point one at a time */
1057 sleep(r->z, rpcattn, r);
1066 while(r->done == 0) {
1067 if(mntrpcread(m, r) < 0)
1077 doread(Mnt *m, int len)
1081 while(qlen(m->q) < len){
1082 b = devtab[m->c->type]->bread(m->c, m->msize, 0);
1085 if(blocklen(b) == 0){
1095 mntrpcread(Mnt *m, Mntrpc *r)
1097 int i, t, len, hlen;
1103 /* read at least length, type, and tag and pullup to a single block */
1104 if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
1106 nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
1108 /* read in the rest of the message, avoid ridiculous (for now) message sizes */
1109 len = GBIT32(nb->rp);
1111 qdiscard(m->q, qlen(m->q));
1114 if(doread(m, len) < 0)
1117 /* pullup the header (i.e. everything except data) */
1118 t = nb->rp[BIT32SZ];
1121 hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
1127 nb = pullupqueue(m->q, hlen);
1129 if(convM2S(nb->rp, len, &r->reply) <= 0){
1130 /* bad message, dump it */
1131 print("mntrpcread: convM2S failed\n");
1132 qdiscard(m->q, len);
1136 /* hang the data off of the fcall struct */
1152 /* split block and put unused bit back */
1154 memmove(nb->wp, b->rp+len, i-len);
1173 for(q = m->queue; q != nil; q = q->list) {
1182 mountmux(Mnt *m, Mntrpc *r)
1189 for(q = *l; q != nil; q = q->list) {
1190 /* look for a reply to a message */
1191 if(q->request.tag == r->reply.tag) {
1195 if(q->iocomfun != nil)
1196 (*q->iocomfun)(q->iocomarg, 1);
1204 * Completed someone else.
1205 * Trade pointers to receive buffer.
1207 q->reply = r->reply;
1220 print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
1224 * Create a new flush request and chain the previous
1228 mntflushalloc(Mntrpc *r)
1232 fr = mntralloc(r->c);
1233 fr->request.type = Tflush;
1234 if(r->request.type == Tflush)
1235 fr->request.oldtag = r->request.oldtag;
1237 fr->request.oldtag = r->request.tag;
1244 * Free a chain of flushes. Remove each unanswered
1245 * flush and the original message from the unanswered
1246 * request queue. Mark the original message as done
1247 * and if it hasn't been answered set the reply to to
1248 * Rflush. Return the original rpc.
1251 mntflushfree(Mnt *m, Mntrpc *r)
1258 r->reply.type = Rflush;
1275 for(i = 0; i < NMASK; i++){
1276 v = mntalloc.tagmask[i];
1279 for(j = 0; j < 1<<TAGSHIFT; j++)
1280 if((v & (1<<j)) == 0){
1281 mntalloc.tagmask[i] |= 1<<j;
1282 return (i<<TAGSHIFT) + j;
1285 panic("no friggin tags left");
1292 mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1300 if(mntalloc.nrpcfree == 0) {
1302 new = malloc(sizeof(Mntrpc));
1304 exhausted("mount rpc header");
1308 new->request.tag = alloctag();
1311 new = mntalloc.rpcfree;
1316 mntalloc.rpcfree = new->list;
1317 mntalloc.nrpcfree--;
1319 mntalloc.nrpcused++;
1333 mntalloc.nrpcused--;
1334 if(mntalloc.nrpcfree < 32) {
1335 r->list = mntalloc.rpcfree;
1336 mntalloc.rpcfree = r;
1337 mntalloc.nrpcfree++;
1341 freetag(r->request.tag);
1348 mntqrm(Mnt *m, Mntrpc *r)
1356 for(f = *l; f != nil; f = f->list) {
1371 /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1373 panic("mntchk 1: nil mchan c %s", chanpath(c));
1377 print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
1380 * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
1382 if(m->id == 0 || m->id >= c->dev)
1383 panic("mntchk 3: can't happen");
1389 * Rewrite channel type and dev for in-flight data to
1390 * reflect local values. These entries are known to be
1391 * the first two in the Dir encoding after the count.
1394 mntdirfix(uchar *dirbuf, Chan *c)
1398 r = devtab[c->type]->dc;
1399 dirbuf += BIT16SZ; /* skip count */
1402 PBIT32(dirbuf, c->dev);
1411 return r->done || r->m->rip == nil;