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 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 */
38 TAGMASK = (1<<TAGSHIFT)-1,
39 NMASK = (64*1024)>>TAGSHIFT,
42 static struct Mntalloc
45 Mnt* list; /* Mount devices in use */
46 Mnt* mntfree; /* Free list */
51 u32int tagmask[NMASK];
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*);
70 #define cachedchan(c) (((c)->flag & CCACHE) != 0 && (c)->mcp != nil)
72 char Esbadstat[] = "invalid directory entry received from server";
73 char Enoversion[] = "version not established for mount channel";
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] */
90 * Version is not multiplexed: message sent only once per connection.
93 mntversion(Chan *c, char *version, int msize, int returnlen)
104 eqlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
106 qunlock(&c->umqlock);
113 if(msize > c->iounit && c->iounit != 0)
116 if(v == nil || v[0] == '\0')
121 error("bad iounit in version call");
122 if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
123 error("bad 9P version specification");
128 qunlock(&c->umqlock);
131 strecpy(buf, buf+sizeof buf, m->version);
133 if(strncmp(buf, v, k) != 0){
134 snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
140 memmove(version, buf, k);
149 msg = malloc(8192+IOHDRSZ);
151 exhausted("version memory");
156 k = convS2M(&f, msg, 8192+IOHDRSZ);
158 error("bad fversion conversion on send");
165 l = devtab[c->type]->write(c, msg, k, oo);
170 error("short write in fversion");
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);
177 error("EOF receiving fversion reply");
183 l = convM2S(msg, k, &f);
185 error("bad fversion conversion on reply");
186 if(f.type != Rversion){
189 error("unexpected reply type in fversion");
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)
202 kstrdup(&v, f.version);
203 q = qopen(10*MAXRPC, 0, nil, nil);
206 exhausted("mount queues");
209 /* now build Mnt associated with this connection */
211 m = mntalloc.mntfree;
213 mntalloc.mntfree = m->list;
216 m = malloc(sizeof(Mnt));
220 exhausted("mount devices");
224 m->list = mntalloc.list;
227 m->id = mntalloc.id++;
233 memmove(version, f.version, k); /* length was checked above */
235 poperror(); /* msg */
248 qunlock(&c->umqlock);
254 mntauth(Chan *c, char *spec)
261 mntversion(c, nil, 0, 0);
269 /* Close must not be called since it will
270 * call mnt recursively
282 r->request.type = Tauth;
283 r->request.afid = c->fid;
284 r->request.uname = up->user;
285 r->request.aname = spec;
288 c->qid = r->reply.aqid;
293 c->iounit = m->msize-IOHDRSZ;
305 mntattach(Chan *c, Chan *ac, char *spec, int flags)
310 if(ac != nil && ac->mchan != c)
315 mntversion(c, nil, 0, 0);
323 /* Close must not be called since it will
324 * call mnt recursively
335 r->request.type = Tattach;
336 r->request.fid = c->fid;
338 r->request.afid = NOFID;
340 r->request.afid = ac->fid;
341 r->request.uname = up->user;
342 r->request.aname = spec;
345 c->qid = r->reply.qid;
372 c = devattach('M', 0);
374 c->dev = mntalloc.id++;
378 panic("mntchan non-zero %p", c->mchan);
383 mntwalk(Chan *c, Chan *nc, char **name, int nname)
391 print("mntwalk: nc != nil\n");
393 error("devmnt: too many name elements");
395 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
397 if(alloc && wq->clone!=nil)
409 * Until the other side accepts this fid, we can't mntclose it.
410 * Therefore set type to 0 for now; rootclose is known to be safe.
413 nc->flag |= (c->flag & CCACHE);
422 r->request.type = Twalk;
423 r->request.fid = c->fid;
424 r->request.newfid = nc->fid;
425 r->request.nwname = nname;
426 memmove(r->request.wname, name, nname*sizeof(char*));
430 if(r->reply.nwqid > nname)
431 error("too many QIDs returned by walk");
432 if(r->reply.nwqid < nname){
436 if(r->reply.nwqid == 0){
443 /* move new fid onto mnt device and update its qid */
444 if(wq->clone != nil){
446 wq->clone->type = c->type;
447 wq->clone->mchan = c->mchan;
450 if(r->reply.nwqid > 0)
451 wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
453 wq->nqid = r->reply.nwqid;
454 for(i=0; i<wq->nqid; i++)
455 wq->qid[i] = r->reply.wqid[i];
465 mntstat(Chan *c, uchar *dp, int n)
478 r->request.type = Tstat;
479 r->request.fid = c->fid;
482 if(r->reply.nstat > n){
484 PBIT16((uchar*)dp, r->reply.nstat-2);
487 memmove(dp, r->reply.stat, n);
497 mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
508 r->request.type = type;
509 r->request.fid = c->fid;
510 r->request.mode = omode;
512 r->request.perm = perm;
513 r->request.name = name;
517 c->qid = r->reply.qid;
519 c->mode = openmode(omode);
520 c->iounit = r->reply.iounit;
521 if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
522 c->iounit = m->msize-IOHDRSZ;
527 if(c->flag & CCACHE){
529 if(type == Tcreate || (omode&OTRUNC) != 0)
537 mntopen(Chan *c, int omode)
539 return mntopencreate(Topen, c, nil, omode, 0);
543 mntcreate(Chan *c, char *name, int omode, ulong perm)
545 return mntopencreate(Tcreate, c, name, omode, perm);
549 mntclunk(Chan *c, int t)
562 r->request.fid = c->fid;
574 while((r = m->queue) != nil){
586 for(f = *l; f != nil; f = f->list) {
593 m->list = mntalloc.mntfree;
594 mntalloc.mntfree = m;
607 mntclunk(c, Tremove);
611 mntwstat(Chan *c, uchar *dp, int n)
622 r->request.type = Twstat;
623 r->request.fid = c->fid;
624 r->request.nstat = n;
625 r->request.stat = dp;
631 if(GBIT64(&dp[STATFIXLEN-4*BIT16SZ-BIT64SZ]) != ~0ULL)
638 mntread(Chan *c, void *buf, long n, vlong off)
644 n = mntrdwr(Tread, c, p, n, off);
645 if(c->qid.type & QTDIR) {
646 for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
647 dirlen = BIT16SZ+GBIT16(p);
650 validstat(p, dirlen);
660 mntwrite(Chan *c, void *buf, long n, vlong off)
662 return mntrdwr(Twrite, c, buf, n, off);
676 off = r->request.offset;
677 switch(r->reply.type){
680 if(m > r->request.count)
681 m = r->request.count;
682 for(b = r->b; m > 0 && b != nil; m -= n, b = b->next) {
686 cupdate(c, b->rp, n, off);
692 if(convM2S(b->rp, BLEN(b), &r->request) == 0)
695 if(m > r->request.count)
696 m = r->request.count;
697 cwrite(c, (uchar*)r->request.data, m, off);
703 mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
719 if(type == Tread && cachedchan(c)) {
720 nr = cread(c, (uchar*)uba, nreq, off);
732 r->request.type = type;
733 r->request.fid = c->fid;
734 r->request.offset = off;
735 r->request.data = uba;
736 r->request.count = nreq;
743 nr = readblist(r->b, (uchar*)uba, nr, 0);
752 if(nr != nreq || n == 0 || up->nnote)
777 tsleep(p, mntprocwork, p, 500);
801 mntdefer(void (*f)(Mntrpc*, void*), Mntrpc *r, void *a)
809 for(i = 0; i < nelem(m->defered); i++){
823 kproc("mntproc", mntproc, p);
835 rahproc(Mntrpc *r, void *a)
855 rahfindrpc(Mntrah *rah, vlong off)
861 for(i=0; i<nelem(rah->r); i++){
862 if((r = rah->r[i]) == nil)
864 n = r->request.count;
865 o = r->request.offset;
866 if(off >= o && off < o+n)
873 mntrahinit(Mntrah *rah)
881 for(i=0; i<nelem(rah->r); i++){
882 if((r = rah->r[i]) != nil){
884 sleep(rah, rahdone, r);
898 mntrahread(Mntrah *rah, Chan *c, uchar *buf, long len, vlong off)
908 if(rahfindrpc(rah, off) == nil)
913 if(rah->seq >= 2*c->iounit){
914 w = (off / c->iounit) * c->iounit;
916 for(o = w; o < e; o += c->iounit){
917 if(rahfindrpc(rah, o) != nil)
920 rr = &rah->r[rah->i % nelem(rah->r)];
921 if((r = *rr) != nil){
922 if(!rahdone(r) || (r->request.offset >= w && r->request.offset < e))
929 r->request.type = Tread;
930 r->request.fid = c->fid;
931 r->request.offset = o;
932 r->request.count = c->iounit;
933 if(!mntdefer(rahproc, r, rah)){
943 while(len > 0 && (r = rahfindrpc(rah, off)) != nil){
945 sleep(rah, rahdone, r);
947 switch(r->reply.type){
953 error(r->reply.ename);
958 n = r->request.count;
959 o = r->request.offset;
960 if(r->reply.count < n)
967 n = readblist(r->b, buf, n, off - o);
982 mountrpc(Mnt *m, Mntrpc *r)
987 r->reply.type = Tmax; /* can't ever be a valid message type */
994 error(r->reply.ename);
998 if(t == r->request.type+1)
1000 print("mnt: proc %s %lud: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
1001 up->text, up->pid, chanpath(m->c), chanpath(r->c),
1002 r, r->request.tag, r->request.fid, r->request.type,
1003 r->reply.type, r->reply.tag);
1009 mountio(Mnt *m, Mntrpc *r)
1017 if(strcmp(up->errstr, Eintr) != 0 || waserror()){
1018 r = mntflushfree(m, r);
1019 switch(r->request.type){
1022 /* botch, abandon fid */
1023 if(strcmp(up->errstr, Ehungup) != 0)
1028 r = mntflushalloc(r);
1039 /* Transmit a file system rpc */
1040 n = sizeS2M(&r->request);
1046 n = convS2M(&r->request, b->wp, n);
1047 if(n <= 0 || n > m->msize) {
1048 print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
1049 up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
1053 if(r->request.type == Twrite && cachedchan(r->c))
1054 r->w = copyblock(b, n);
1056 devtab[m->c->type]->bwrite(m->c, b, 0);
1058 /* Gate readers onto the mount point one at a time */
1064 sleep(r->z, rpcattn, r);
1073 while(r->done == 0) {
1074 if(mntrpcread(m, r) < 0)
1084 doread(Mnt *m, int len)
1088 while(qlen(m->q) < len){
1089 b = devtab[m->c->type]->bread(m->c, m->msize, 0);
1090 if(b == nil || qaddlist(m->q, b) == 0)
1097 mntrpcread(Mnt *m, Mntrpc *r)
1099 int i, t, len, hlen;
1105 /* read at least length, type, and tag and pullup to a single block */
1106 if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
1108 nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
1110 /* read in the rest of the message, avoid ridiculous (for now) message sizes */
1111 len = GBIT32(nb->rp);
1113 qdiscard(m->q, qlen(m->q));
1116 if(doread(m, len) < 0)
1119 /* pullup the header (i.e. everything except data) */
1120 t = nb->rp[BIT32SZ];
1123 hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
1129 nb = pullupqueue(m->q, hlen);
1131 if(convM2S(nb->rp, len, &r->reply) <= 0){
1132 /* bad message, dump it */
1133 print("mntrpcread: convM2S failed\n");
1134 qdiscard(m->q, len);
1138 /* hang the data off of the fcall struct */
1154 /* split block and put unused bit back */
1156 memmove(nb->wp, b->rp+len, i-len);
1175 for(q = m->queue; q != nil; q = q->list) {
1184 mountmux(Mnt *m, Mntrpc *r)
1191 for(q = *l; q != nil; q = q->list) {
1192 /* look for a reply to a message */
1193 if(q->request.tag == r->reply.tag) {
1201 * Completed someone else.
1202 * Trade pointers to receive buffer.
1204 q->reply = r->reply;
1217 print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
1221 * Create a new flush request and chain the previous
1225 mntflushalloc(Mntrpc *r)
1229 fr = mntralloc(r->c);
1230 fr->request.type = Tflush;
1231 if(r->request.type == Tflush)
1232 fr->request.oldtag = r->request.oldtag;
1234 fr->request.oldtag = r->request.tag;
1241 * Free a chain of flushes. Remove each unanswered
1242 * flush and the original message from the unanswered
1243 * request queue. Mark the original message as done
1244 * and if it hasn't been answered set the reply to to
1245 * Rflush. Return the original rpc.
1248 mntflushfree(Mnt *m, Mntrpc *r)
1255 r->reply.type = Rflush;
1272 for(i = 0; i < NMASK; i++){
1273 v = mntalloc.tagmask[i];
1276 for(j = 0; (v & 1) != 0; j++)
1278 mntalloc.tagmask[i] |= 1<<j;
1279 return i<<TAGSHIFT | j;
1281 panic("no friggin tags left");
1288 mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1296 if(mntalloc.nrpcfree == 0) {
1298 new = malloc(sizeof(Mntrpc));
1300 exhausted("mount rpc header");
1302 new->request.tag = alloctag();
1305 new = mntalloc.rpcfree;
1310 mntalloc.rpcfree = new->list;
1311 mntalloc.nrpcfree--;
1313 mntalloc.nrpcused++;
1329 mntalloc.nrpcused--;
1330 if(mntalloc.nrpcfree < 32) {
1331 r->list = mntalloc.rpcfree;
1332 mntalloc.rpcfree = r;
1333 mntalloc.nrpcfree++;
1337 freetag(r->request.tag);
1343 mntqrm(Mnt *m, Mntrpc *r)
1351 for(f = *l; f != nil; f = f->list) {
1366 /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1368 panic("mntchk 1: nil mchan c %s", chanpath(c));
1372 print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
1375 * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
1377 if(m->id == 0 || m->id >= c->dev)
1378 panic("mntchk 3: can't happen");
1384 * Rewrite channel type and dev for in-flight data to
1385 * reflect local values. These entries are known to be
1386 * the first two in the Dir encoding after the count.
1389 mntdirfix(uchar *dirbuf, Chan *c)
1393 r = devtab[c->type]->dc;
1394 dirbuf += BIT16SZ; /* skip count */
1397 PBIT32(dirbuf, c->dev);
1406 return r->done || r->m->rip == nil;