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)
312 mntversion(c, nil, 0, 0);
320 /* Close must not be called since it will
321 * call mnt recursively
332 r->request.type = Tattach;
333 r->request.fid = c->fid;
335 r->request.afid = NOFID;
337 r->request.afid = ac->fid;
338 r->request.uname = up->user;
339 r->request.aname = spec;
342 c->qid = r->reply.qid;
369 c = devattach('M', 0);
371 c->dev = mntalloc.id++;
375 panic("mntchan non-zero %p", c->mchan);
380 mntwalk(Chan *c, Chan *nc, char **name, int nname)
388 print("mntwalk: nc != nil\n");
390 error("devmnt: too many name elements");
392 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
394 if(alloc && wq->clone!=nil)
406 * Until the other side accepts this fid, we can't mntclose it.
407 * Therefore set type to 0 for now; rootclose is known to be safe.
410 nc->flag |= (c->flag & CCACHE);
419 r->request.type = Twalk;
420 r->request.fid = c->fid;
421 r->request.newfid = nc->fid;
422 r->request.nwname = nname;
423 memmove(r->request.wname, name, nname*sizeof(char*));
427 if(r->reply.nwqid > nname)
428 error("too many QIDs returned by walk");
429 if(r->reply.nwqid < nname){
433 if(r->reply.nwqid == 0){
440 /* move new fid onto mnt device and update its qid */
441 if(wq->clone != nil){
443 wq->clone->type = c->type;
444 wq->clone->mchan = c->mchan;
447 if(r->reply.nwqid > 0)
448 wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
450 wq->nqid = r->reply.nwqid;
451 for(i=0; i<wq->nqid; i++)
452 wq->qid[i] = r->reply.wqid[i];
462 mntstat(Chan *c, uchar *dp, int n)
475 r->request.type = Tstat;
476 r->request.fid = c->fid;
479 if(r->reply.nstat > n){
481 PBIT16((uchar*)dp, r->reply.nstat-2);
484 memmove(dp, r->reply.stat, n);
494 mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
505 r->request.type = type;
506 r->request.fid = c->fid;
507 r->request.mode = omode;
509 r->request.perm = perm;
510 r->request.name = name;
514 c->qid = r->reply.qid;
516 c->mode = openmode(omode);
517 c->iounit = r->reply.iounit;
518 if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
519 c->iounit = m->msize-IOHDRSZ;
524 if(c->flag & CCACHE){
526 if(type == Tcreate || (omode&OTRUNC) != 0)
534 mntopen(Chan *c, int omode)
536 return mntopencreate(Topen, c, nil, omode, 0);
540 mntcreate(Chan *c, char *name, int omode, ulong perm)
542 return mntopencreate(Tcreate, c, name, omode, perm);
546 mntclunk(Chan *c, int t)
559 r->request.fid = c->fid;
571 while((r = m->queue) != nil){
583 for(f = *l; f != nil; f = f->list) {
590 m->list = mntalloc.mntfree;
591 mntalloc.mntfree = m;
604 mntclunk(c, Tremove);
608 mntwstat(Chan *c, uchar *dp, int n)
619 r->request.type = Twstat;
620 r->request.fid = c->fid;
621 r->request.nstat = n;
622 r->request.stat = dp;
628 if(GBIT64(&dp[STATFIXLEN-4*BIT16SZ-BIT64SZ]) != ~0ULL)
635 mntread(Chan *c, void *buf, long n, vlong off)
641 n = mntrdwr(Tread, c, p, n, off);
642 if(c->qid.type & QTDIR) {
643 for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
644 dirlen = BIT16SZ+GBIT16(p);
647 validstat(p, dirlen);
657 mntwrite(Chan *c, void *buf, long n, vlong off)
659 return mntrdwr(Twrite, c, buf, n, off);
673 off = r->request.offset;
674 switch(r->reply.type){
677 if(m > r->request.count)
678 m = r->request.count;
679 for(b = r->b; m > 0 && b != nil; m -= n, b = b->next) {
683 cupdate(c, b->rp, n, off);
689 if(convM2S(b->rp, BLEN(b), &r->request) == 0)
692 if(m > r->request.count)
693 m = r->request.count;
694 cwrite(c, (uchar*)r->request.data, m, off);
700 mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
716 if(type == Tread && cachedchan(c)) {
717 nr = cread(c, (uchar*)uba, nreq, off);
729 r->request.type = type;
730 r->request.fid = c->fid;
731 r->request.offset = off;
732 r->request.data = uba;
733 r->request.count = nreq;
740 nr = readblist(r->b, (uchar*)uba, nr, 0);
749 if(nr != nreq || n == 0 || up->nnote)
774 tsleep(p, mntprocwork, p, 500);
798 mntdefer(void (*f)(Mntrpc*, void*), Mntrpc *r, void *a)
806 for(i = 0; i < nelem(m->defered); i++){
820 kproc("mntproc", mntproc, p);
832 rahproc(Mntrpc *r, void *a)
852 rahfindrpc(Mntrah *rah, vlong off)
858 for(i=0; i<nelem(rah->r); i++){
859 if((r = rah->r[i]) == nil)
861 n = r->request.count;
862 o = r->request.offset;
863 if(off >= o && off < o+n)
870 mntrahinit(Mntrah *rah)
878 for(i=0; i<nelem(rah->r); i++){
879 if((r = rah->r[i]) != nil){
881 sleep(rah, rahdone, r);
895 mntrahread(Mntrah *rah, Chan *c, uchar *buf, long len, vlong off)
905 if(rahfindrpc(rah, off) == nil)
910 if(rah->seq >= 2*c->iounit){
911 w = (off / c->iounit) * c->iounit;
913 for(o = w; o < e; o += c->iounit){
914 if(rahfindrpc(rah, o) != nil)
917 rr = &rah->r[rah->i % nelem(rah->r)];
918 if((r = *rr) != nil){
919 if(!rahdone(r) || (r->request.offset >= w && r->request.offset < e))
926 r->request.type = Tread;
927 r->request.fid = c->fid;
928 r->request.offset = o;
929 r->request.count = c->iounit;
930 if(!mntdefer(rahproc, r, rah)){
940 while(len > 0 && (r = rahfindrpc(rah, off)) != nil){
942 sleep(rah, rahdone, r);
944 switch(r->reply.type){
950 error(r->reply.ename);
955 n = r->request.count;
956 o = r->request.offset;
957 if(r->reply.count < n)
964 n = readblist(r->b, buf, n, off - o);
979 mountrpc(Mnt *m, Mntrpc *r)
984 r->reply.type = Tmax; /* can't ever be a valid message type */
991 error(r->reply.ename);
995 if(t == r->request.type+1)
997 print("mnt: proc %s %lud: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
998 up->text, up->pid, chanpath(m->c), chanpath(r->c),
999 r, r->request.tag, r->request.fid, r->request.type,
1000 r->reply.type, r->reply.tag);
1006 mountio(Mnt *m, Mntrpc *r)
1014 if(strcmp(up->errstr, Eintr) != 0 || waserror()){
1015 r = mntflushfree(m, r);
1016 switch(r->request.type){
1019 /* botch, abandon fid */
1020 if(strcmp(up->errstr, Ehungup) != 0)
1025 r = mntflushalloc(r);
1036 /* Transmit a file system rpc */
1037 n = sizeS2M(&r->request);
1043 n = convS2M(&r->request, b->wp, n);
1044 if(n <= 0 || n > m->msize) {
1045 print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
1046 up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
1050 if(r->request.type == Twrite && cachedchan(r->c))
1051 r->w = copyblock(b, n);
1053 devtab[m->c->type]->bwrite(m->c, b, 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);
1087 if(b == nil || qaddlist(m->q, b) == 0)
1094 mntrpcread(Mnt *m, Mntrpc *r)
1096 int i, t, len, hlen;
1102 /* read at least length, type, and tag and pullup to a single block */
1103 if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
1105 nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
1107 /* read in the rest of the message, avoid ridiculous (for now) message sizes */
1108 len = GBIT32(nb->rp);
1110 qdiscard(m->q, qlen(m->q));
1113 if(doread(m, len) < 0)
1116 /* pullup the header (i.e. everything except data) */
1117 t = nb->rp[BIT32SZ];
1120 hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
1126 nb = pullupqueue(m->q, hlen);
1128 if(convM2S(nb->rp, len, &r->reply) <= 0){
1129 /* bad message, dump it */
1130 print("mntrpcread: convM2S failed\n");
1131 qdiscard(m->q, len);
1135 /* hang the data off of the fcall struct */
1151 /* split block and put unused bit back */
1153 memmove(nb->wp, b->rp+len, i-len);
1172 for(q = m->queue; q != nil; q = q->list) {
1181 mountmux(Mnt *m, Mntrpc *r)
1188 for(q = *l; q != nil; q = q->list) {
1189 /* look for a reply to a message */
1190 if(q->request.tag == r->reply.tag) {
1198 * Completed someone else.
1199 * Trade pointers to receive buffer.
1201 q->reply = r->reply;
1214 print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
1218 * Create a new flush request and chain the previous
1222 mntflushalloc(Mntrpc *r)
1226 fr = mntralloc(r->c);
1227 fr->request.type = Tflush;
1228 if(r->request.type == Tflush)
1229 fr->request.oldtag = r->request.oldtag;
1231 fr->request.oldtag = r->request.tag;
1238 * Free a chain of flushes. Remove each unanswered
1239 * flush and the original message from the unanswered
1240 * request queue. Mark the original message as done
1241 * and if it hasn't been answered set the reply to to
1242 * Rflush. Return the original rpc.
1245 mntflushfree(Mnt *m, Mntrpc *r)
1252 r->reply.type = Rflush;
1269 for(i = 0; i < NMASK; i++){
1270 v = mntalloc.tagmask[i];
1273 for(j = 0; (v & 1) != 0; j++)
1275 mntalloc.tagmask[i] |= 1<<j;
1276 return i<<TAGSHIFT | j;
1278 panic("no friggin tags left");
1285 mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1293 if(mntalloc.nrpcfree == 0) {
1295 new = malloc(sizeof(Mntrpc));
1297 exhausted("mount rpc header");
1299 new->request.tag = alloctag();
1302 new = mntalloc.rpcfree;
1307 mntalloc.rpcfree = new->list;
1308 mntalloc.nrpcfree--;
1310 mntalloc.nrpcused++;
1326 mntalloc.nrpcused--;
1327 if(mntalloc.nrpcfree < 32) {
1328 r->list = mntalloc.rpcfree;
1329 mntalloc.rpcfree = r;
1330 mntalloc.nrpcfree++;
1334 freetag(r->request.tag);
1340 mntqrm(Mnt *m, Mntrpc *r)
1348 for(f = *l; f != nil; f = f->list) {
1363 /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1365 panic("mntchk 1: nil mchan c %s", chanpath(c));
1369 print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
1372 * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
1374 if(m->id == 0 || m->id >= c->dev)
1375 panic("mntchk 3: can't happen");
1381 * Rewrite channel type and dev for in-flight data to
1382 * reflect local values. These entries are known to be
1383 * the first two in the Dir encoding after the count.
1386 mntdirfix(uchar *dirbuf, Chan *c)
1390 r = devtab[c->type]->dc;
1391 dirbuf += BIT16SZ; /* skip count */
1394 PBIT32(dirbuf, c->dev);
1403 return r->done || r->m->rip == nil;