|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "../port/error.h"
7: #include "devtab.h"
8:
9: typedef struct Mntrpc Mntrpc;
10: struct Mntrpc
11: {
12: Mntrpc *list; /* Free/pending list */
13: Fcall request; /* Outgoing file system protocol message */
14: Fcall reply; /* Incoming reply */
15: Mnt *m; /* Mount device during rpc */
16: Rendez r; /* Place to hang out */
17: char *rpc; /* I/O Data buffer */
18: char done; /* Rpc completed */
19: char flushed; /* Flush was sent */
20: ushort flushtag; /* Tag flush sent on */
21: char flush[MAXMSG]; /* Somewhere to build flush */
22: };
23:
24: struct Mnt
25: {
26: int reads; /* counters for debugging */
27: int writes;
28: int readerrs;
29: int badlen;
30: int goodconv;
31: int noone;
32:
33: Ref; /* Count of attached channels */
34: Chan *c; /* Channel to file service */
35: Proc *rip; /* Reader in progress */
36: Mntrpc *queue; /* Queue of pending requests on this channel */
37: ulong id; /* Multiplexor id for channel check */
38: Mnt *list; /* Free list */
39: char mux; /* Set if the device does the multiplexing */
40: int blocksize; /* read/write block size */
41: ushort flushtag; /* Tag to send flush on */
42: ushort flushbase; /* Base tag of flush window for this buffer */
43: };
44:
45: struct Mntalloc
46: {
47: Lock;
48: Mnt *list; /* Mount devices in used */
49: Mnt *mntfree; /* Free list */
50: Mntrpc *rpcfree;
51: int id;
52: int rpctag;
53: }mntalloc;
54:
55: #define MAXRPC (MAXFDATA+MAXMSG)
56: #define limit(n, max) (n > max ? max : n)
57:
58: Chan* mattach(Mnt*, char*);
59: Mnt* mntchk(Chan*);
60: void mntdirfix(uchar*, Chan*);
61: void mntdoclunk(Mnt *, Mntrpc *);
62: int mntflush(Mnt*, Mntrpc*);
63: void mntfree(Mntrpc*);
64: void mntgate(Mnt*);
65: void mntpntfree(Mnt*);
66: void mntqrm(Mnt*, Mntrpc*);
67: Mntrpc* mntralloc(void);
68: long mntrdwr(int , Chan*, void*,long , ulong);
69: void mntrpcread(Mnt*, Mntrpc*);
70: void mountio(Mnt*, Mntrpc*);
71: void mountmux(Mnt*, Mntrpc*);
72: void mountrpc(Mnt*, Mntrpc*);
73: int rpcattn(Mntrpc*);
74: void mclose(Mnt*);
75:
76: static int defblocksize = MAXFDATA;
77:
78: enum
79: {
80: Tagspace = 1,
81: Tagfls = 0x8000,
82: Tagend = 0xfffe,
83:
84: ALIGN = 256, /* Vme block mode alignment */
85: };
86:
87: void
88: mntblocksize(int s)
89: {
90: if(s < 256 || s > MAXFDATA)
91: return;
92: defblocksize = s;
93: }
94:
95: void
96: mntreset(void)
97: {
98: mntalloc.id = 1;
99: mntalloc.rpctag = Tagspace;
100: }
101:
102: void
103: mntinit(void)
104: {
105: }
106:
107: Chan*
108: mntattach(char *muxattach)
109: {
110: Mnt *m;
111: Chan *c, *mc;
112: struct bogus{
113: Chan *chan;
114: char *spec;
115: }bogus;
116:
117: bogus = *((struct bogus *)muxattach);
118: c = bogus.chan;
119:
120: lock(&mntalloc);
121: for(m = mntalloc.list; m; m = m->list) {
122: if(m->c == c && m->id) {
123: lock(m);
124: if(m->id && m->ref > 0 && m->c == c) {
125: unlock(&mntalloc);
126: m->ref++;
127: unlock(m);
128: return mattach(m, bogus.spec);
129: }
130: unlock(m);
131: }
132: }
133:
134: m = mntalloc.mntfree;
135: if(m != 0)
136: mntalloc.mntfree = m->list;
137: else {
138: m = malloc(sizeof(Mnt));
139: if(m == 0) {
140: unlock(&mntalloc);
141: exhausted("mount devices");
142: }
143: m->flushbase = Tagfls;
144: m->flushtag = Tagfls;
145: }
146: m->list = mntalloc.list;
147: mntalloc.list = m;
148: m->id = mntalloc.id++;
149: lock(m);
150: unlock(&mntalloc);
151:
152: m->ref = 1;
153: m->queue = 0;
154: m->rip = 0;
155: m->c = c;
156: m->c->flag |= CMSG;
157: m->blocksize = defblocksize;
158:
159: switch(devchar[m->c->type]) {
160: default:
161: m->mux = 0;
162: break;
163: case 'C': /* Cyclone */
164: m->mux = 1;
165: break;
166: }
167: incref(m->c);
168: unlock(m);
169:
170: if(waserror()) {
171: mclose(m);
172: nexterror();
173: }
174:
175: c = mattach(m, bogus.spec);
176:
177: /*
178: * If exportfs mounts on behalf of a local devmnt, the mount
179: * point is folded onto the original channel to preserve a single
180: * fid/tag space. CHDIR is cleared by exportfs to indicate it
181: * is supplying the mount.
182: */
183: mc = m->c;
184: if(mc->type == devno('M', 0) && (c->qid.path&CHDIR) == 0) {
185: c->qid.path |= CHDIR;
186: c->mntptr = mc->mntptr;
187: c->mchan = mc->mntptr->c;
188: c->mqid = c->qid;
189: incref(c->mntptr);
190: mclose(m);
191: }
192:
193: poperror();
194: return c;
195: }
196:
197: Chan *
198: mattach(Mnt *m, char *spec)
199: {
200: Chan *c;
201: Mntrpc *r;
202: ulong id;
203:
204: r = mntralloc();
205: c = devattach('M', spec);
206: lock(&mntalloc);
207: c->dev = mntalloc.id++;
208: unlock(&mntalloc);
209: c->mntptr = m;
210:
211: if(waserror()){
212: mntfree(r);
213: /* Close must not be called since
214: * it will call mnt recursively
215: */
216: chanfree(c);
217: nexterror();
218: }
219:
220: r->request.type = Tattach;
221: r->request.fid = c->fid;
222: memmove(r->request.uname, u->p->user, NAMELEN);
223: strncpy(r->request.aname, spec, NAMELEN);
224: id = authrequest(m->c->session, &r->request);
225: mountrpc(m, r);
226: authreply(m->c->session, id, &r->reply);
227:
228: c->qid = r->reply.qid;
229: c->mchan = m->c;
230: c->mqid = c->qid;
231: poperror();
232: mntfree(r);
233: return c;
234: }
235:
236: Chan*
237: mntclone(Chan *c, Chan *nc)
238: {
239: Mnt *m;
240: Mntrpc *r;
241: int alloc = 0;
242:
243: m = mntchk(c);
244: r = mntralloc();
245: if(nc == 0) {
246: nc = newchan();
247: alloc = 1;
248: }
249: if(waserror()) {
250: mntfree(r);
251: if(alloc)
252: close(nc);
253: nexterror();
254: }
255:
256: r->request.type = Tclone;
257: r->request.fid = c->fid;
258: r->request.newfid = nc->fid;
259: mountrpc(m, r);
260:
261: devclone(c, nc);
262: nc->mqid = c->qid;
263: incref(m);
264:
265: USED(alloc);
266: poperror();
267: mntfree(r);
268: return nc;
269: }
270:
271: int
272: mntwalk(Chan *c, char *name)
273: {
274: Mnt *m;
275: Mntrpc *r;
276:
277: m = mntchk(c);
278: r = mntralloc();
279: if(waserror()) {
280: mntfree(r);
281: return 0;
282: }
283: r->request.type = Twalk;
284: r->request.fid = c->fid;
285: strncpy(r->request.name, name, NAMELEN);
286: mountrpc(m, r);
287:
288: c->qid = r->reply.qid;
289:
290: poperror();
291: mntfree(r);
292: return 1;
293: }
294:
295: void
296: mntstat(Chan *c, char *dp)
297: {
298: Mnt *m;
299: Mntrpc *r;
300:
301: m = mntchk(c);
302: r = mntralloc();
303: if(waserror()) {
304: mntfree(r);
305: nexterror();
306: }
307: r->request.type = Tstat;
308: r->request.fid = c->fid;
309: mountrpc(m, r);
310:
311: memmove(dp, r->reply.stat, DIRLEN);
312: mntdirfix((uchar*)dp, c);
313: poperror();
314: mntfree(r);
315: }
316:
317: Chan*
318: mntopen(Chan *c, int omode)
319: {
320: Mnt *m;
321: Mntrpc *r;
322:
323: m = mntchk(c);
324: r = mntralloc();
325: if(waserror()) {
326: mntfree(r);
327: nexterror();
328: }
329: r->request.type = Topen;
330: r->request.fid = c->fid;
331: r->request.mode = omode;
332: mountrpc(m, r);
333:
334: c->qid = r->reply.qid;
335: c->offset = 0;
336: c->mode = openmode(omode);
337: c->flag |= COPEN;
338: poperror();
339: mntfree(r);
340: return c;
341: }
342:
343: void
344: mntcreate(Chan *c, char *name, int omode, ulong perm)
345: {
346: Mnt *m;
347: Mntrpc *r;
348:
349: m = mntchk(c);
350: r = mntralloc();
351: if(waserror()) {
352: mntfree(r);
353: nexterror();
354: }
355: r->request.type = Tcreate;
356: r->request.fid = c->fid;
357: r->request.mode = omode;
358: r->request.perm = perm;
359: strncpy(r->request.name, name, NAMELEN);
360: mountrpc(m, r);
361:
362: c->qid = r->reply.qid;
363: c->flag |= COPEN;
364: c->mode = openmode(omode);
365: poperror();
366: mntfree(r);
367: }
368:
369: void
370: mntclunk(Chan *c, int t)
371: {
372: Mnt *m;
373: Mntrpc *r;
374:
375: m = mntchk(c);
376: r = mntralloc();
377: if(waserror()){
378: mntdoclunk(m, r);
379: nexterror();
380: }
381:
382: r->request.type = t;
383: r->request.fid = c->fid;
384: mountrpc(m, r);
385: mntdoclunk(m, r);
386: poperror();
387: }
388:
389: void
390: mclose(Mnt *m)
391: {
392: Mntrpc *q, *r;
393:
394: if(decref(m) != 0)
395: return;
396:
397: for(q = m->queue; q; q = r) {
398: r = q->list;
399: q->flushed = 0;
400: mntfree(q);
401: }
402: m->id = 0;
403: close(m->c);
404: mntpntfree(m);
405: }
406:
407: void
408: mntdoclunk(Mnt *m, Mntrpc *r)
409: {
410: mntfree(r);
411: mclose(m);
412: }
413:
414: void
415: mntpntfree(Mnt *m)
416: {
417: Mnt *f, **l;
418:
419: lock(&mntalloc);
420: l = &mntalloc.list;
421: for(f = *l; f; f = f->list) {
422: if(f == m) {
423: *l = m->list;
424: break;
425: }
426: l = &f->list;
427: }
428:
429: m->list = mntalloc.mntfree;
430: mntalloc.mntfree = m;
431: unlock(&mntalloc);
432: }
433:
434: void
435: mntclose(Chan *c)
436: {
437: mntclunk(c, Tclunk);
438: }
439:
440: void
441: mntremove(Chan *c)
442: {
443: mntclunk(c, Tremove);
444: }
445:
446: void
447: mntwstat(Chan *c, char *dp)
448: {
449: Mnt *m;
450: Mntrpc *r;
451:
452: m = mntchk(c);
453: r = mntralloc();
454: if(waserror()) {
455: mntfree(r);
456: nexterror();
457: }
458: r->request.type = Twstat;
459: r->request.fid = c->fid;
460: memmove(r->request.stat, dp, DIRLEN);
461: mountrpc(m, r);
462: poperror();
463: mntfree(r);
464: }
465:
466: long
467: mntread(Chan *c, void *buf, long n, ulong offset)
468: {
469: uchar *p, *e;
470:
471: n = mntrdwr(Tread, c, buf, n, offset);
472: if(c->qid.path & CHDIR)
473: for(p = (uchar*)buf, e = &p[n]; p < e; p += DIRLEN)
474: mntdirfix(p, c);
475:
476: return n;
477: }
478:
479: long
480: mntwrite(Chan *c, void *buf, long n, ulong offset)
481: {
482: return mntrdwr(Twrite, c, buf, n, offset);
483: }
484:
485: long
486: mntrdwr(int type, Chan *c, void *buf, long n, ulong offset)
487: {
488: Mnt *m;
489: Mntrpc *r;
490: char *uba;
491: ulong cnt, nr;
492:
493: m = mntchk(c);
494: uba = buf;
495: cnt = 0;
496: for(;;) {
497: r = mntralloc();
498: if(waserror()) {
499: mntfree(r);
500: nexterror();
501: }
502: r->request.type = type;
503: r->request.fid = c->fid;
504: r->request.offset = offset;
505: r->request.data = uba;
506: r->request.count = limit(n, m->blocksize);
507: mountrpc(m, r);
508: nr = r->reply.count;
509: if(nr > r->request.count)
510: nr = r->request.count;
511: if(type == Tread)
512: memmove(uba, r->reply.data, nr);
513: poperror();
514: mntfree(r);
515: offset += nr;
516: uba += nr;
517: cnt += nr;
518: n -= nr;
519: if(nr != r->request.count || n == 0 || u->nnote)
520: break;
521: }
522: return cnt;
523: }
524:
525: void
526: mountrpc(Mnt *m, Mntrpc *r)
527: {
528: r->reply.tag = 0; /* poison the old values */
529: r->reply.type = 4;
530:
531: mountio(m, r);
532: if(r->reply.type == Rerror)
533: error(r->reply.ename);
534:
535: if(r->reply.type == Rflush)
536: error(Eintr);
537:
538: if(r->reply.type != r->request.type+1) {
539: print("mnt: mismatched reply 0x%lux T%d R%d tags req %d fls %d rep %d\n",
540: r, r->request.type, r->reply.type, r->request.tag,
541: r->flushtag, r->reply.tag);
542:
543: error(Emountrpc);
544: }
545: }
546:
547: void
548: mountio(Mnt *m, Mntrpc *r)
549: {
550: int n;
551:
552: lock(m);
553: r->flushed = 0;
554: r->m = m;
555: r->list = m->queue;
556: m->queue = r;
557: unlock(m);
558:
559: /* Transmit a file system rpc */
560: n = convS2M(&r->request, r->rpc);
561: if(waserror()) {
562: if(mntflush(m, r) == 0)
563: nexterror();
564: }
565: else {
566: if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n)
567: error(Emountrpc);
568: m->writes++;
569: poperror();
570: }
571: if(m->mux) {
572: mntqrm(m, r);
573: mntrpcread(m, r);
574: return;
575: }
576:
577: /* Gate readers onto the mount point one at a time */
578: for(;;) {
579: lock(m);
580: if(m->rip == 0)
581: break;
582: unlock(m);
583: if(waserror()) {
584: if(mntflush(m, r) == 0)
585: nexterror();
586: continue;
587: }
588: sleep(&r->r, rpcattn, r);
589: poperror();
590: if(r->done)
591: return;
592: }
593: m->rip = u->p;
594: unlock(m);
595: while(r->done == 0) {
596: mntrpcread(m, r);
597: mountmux(m, r);
598: }
599: mntgate(m);
600: }
601:
602: void
603: mntrpcread(Mnt *m, Mntrpc *r)
604: {
605: int n;
606:
607: for(;;) {
608: if(waserror()) {
609: m->readerrs++;
610: if(mntflush(m, r) == 0) {
611: if(m->mux == 0)
612: mntgate(m);
613: nexterror();
614: }
615: continue;
616: }
617: r->reply.type = 0;
618: r->reply.tag = 0;
619: n = (*devtab[m->c->type].read)(m->c, r->rpc, MAXRPC, 0);
620: poperror();
621: m->reads++;
622: if(n == 0){
623: m->badlen++;
624: continue;
625: }
626:
627: if(convM2S(r->rpc, &r->reply, n) != 0){
628: m->goodconv++;
629: return;
630: }
631: }
632: }
633:
634: void
635: mntgate(Mnt *m)
636: {
637: Mntrpc *q;
638:
639: lock(m);
640: m->rip = 0;
641: for(q = m->queue; q; q = q->list)
642: if(q->done == 0) {
643: lock(&q->r);
644: if(q->r.p) {
645: unlock(&q->r);
646: unlock(m);
647: wakeup(&q->r);
648: return;
649: }
650: unlock(&q->r);
651: }
652: unlock(m);
653: }
654:
655: void
656: mountmux(Mnt *m, Mntrpc *r)
657: {
658: char *dp;
659: Mntrpc **l, *q;
660:
661: lock(m);
662: l = &m->queue;
663: for(q = *l; q; q = q->list) {
664: if(q->request.tag == r->reply.tag
665: || q->flushed && q->flushtag == r->reply.tag) {
666: *l = q->list;
667: unlock(m);
668: if(q != r) { /* Completed someone else */
669: dp = q->rpc;
670: q->rpc = r->rpc;
671: r->rpc = dp;
672: memmove(&q->reply, &r->reply, sizeof(Fcall));
673: q->done = 1;
674: wakeup(&q->r);
675: }else
676: q->done = 1;
677: return;
678: }
679: l = &q->list;
680: }
681: m->noone++;
682: unlock(m);
683: }
684:
685: int
686: mntflush(Mnt *m, Mntrpc *r)
687: {
688: int n;
689: Fcall flush;
690:
691: lock(m);
692: r->flushtag = m->flushtag++;
693: if(m->flushtag == Tagend)
694: m->flushtag = m->flushbase;
695: r->flushed = 1;
696: unlock(m);
697:
698: flush.type = Tflush;
699: flush.tag = r->flushtag;
700: flush.oldtag = r->request.tag;
701: n = convS2M(&flush, r->flush);
702:
703: if(waserror()) {
704: if(strcmp(u->error, Eintr) == 0)
705: return 1;
706: mntqrm(m, r);
707: return 0;
708: }
709: (*devtab[m->c->type].write)(m->c, r->flush, n, 0);
710: poperror();
711: return 1;
712: }
713:
714: Mntrpc *
715: mntralloc(void)
716: {
717: Mntrpc *new;
718:
719: lock(&mntalloc);
720: new = mntalloc.rpcfree;
721: if(new != 0)
722: mntalloc.rpcfree = new->list;
723: else {
724: new = xalloc(sizeof(Mntrpc)+MAXRPC);
725: if(new == 0) {
726: unlock(&mntalloc);
727: exhausted("mount rpc buffer");
728: }
729: new->rpc = (char*)new+sizeof(Mntrpc);
730: new->request.tag = mntalloc.rpctag++;
731: }
732: unlock(&mntalloc);
733: new->done = 0;
734: new->flushed = 0;
735: return new;
736: }
737:
738: void
739: mntfree(Mntrpc *r)
740: {
741: lock(&mntalloc);
742: r->list = mntalloc.rpcfree;
743: mntalloc.rpcfree = r;
744: unlock(&mntalloc);
745: }
746:
747: void
748: mntqrm(Mnt *m, Mntrpc *r)
749: {
750: Mntrpc **l, *f;
751:
752: lock(m);
753: r->done = 1;
754: r->flushed = 0;
755:
756: l = &m->queue;
757: for(f = *l; f; f = f->list) {
758: if(f == r) {
759: *l = r->list;
760: break;
761: }
762: l = &f->list;
763: }
764: unlock(m);
765: }
766:
767: Mnt *
768: mntchk(Chan *c)
769: {
770: Mnt *m;
771:
772: m = c->mntptr;
773: /* Was it closed and reused ? */
774: if(m->id == 0 || m->id >= c->dev) /* Sanity check */
775: error(Eshutdown);
776: return m;
777: }
778:
779: void
780: mntdirfix(uchar *dirbuf, Chan *c)
781: {
782: dirbuf[DIRLEN-4] = devchar[c->type]>>0;
783: dirbuf[DIRLEN-3] = devchar[c->type]>>8;
784: dirbuf[DIRLEN-2] = c->dev;
785: dirbuf[DIRLEN-1] = c->dev>>8;
786: }
787:
788: int
789: rpcattn(Mntrpc *r)
790: {
791: return r->done || r->m->rip == 0;
792: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.