7 typedef struct Fid Fid;
8 typedef struct Export Export;
9 typedef struct Exq Exq;
10 typedef struct Exwork Exwork;
16 Maxrpc = IOHDRSZ + Maxfdata,
25 int io; /* fd to read/write */
38 int ref; /* fcalls using the fid; locked by Export.Lock */
39 int attached; /* fid attached or cloned but not clunked */
45 int responding; /* writing out reply message */
46 int noresponse; /* don't respond to this one */
48 int shut; /* has been noted for shutdown */
61 int nwaiters; /* queue of slaves waiting for work */
65 Exq *head; /* work waiting for a slave */
71 static void exshutdown(Export*);
72 static void exflush(Export*, int, int);
73 static void exslave(void*);
74 static void exfree(Export*);
75 static void exportproc(Export*);
77 static char* Exattach(Export*, Fcall*, uchar*);
78 static char* Exauth(Export*, Fcall*, uchar*);
79 static char* Exclunk(Export*, Fcall*, uchar*);
80 static char* Excreate(Export*, Fcall*, uchar*);
81 static char* Exversion(Export*, Fcall*, uchar*);
82 static char* Exopen(Export*, Fcall*, uchar*);
83 static char* Exread(Export*, Fcall*, uchar*);
84 static char* Exremove(Export*, Fcall*, uchar*);
85 static char* Exsession(Export*, Fcall*, uchar*);
86 static char* Exstat(Export*, Fcall*, uchar*);
87 static char* Exwalk(Export*, Fcall*, uchar*);
88 static char* Exwrite(Export*, Fcall*, uchar*);
89 static char* Exwstat(Export*, Fcall*, uchar*);
91 static char *(*fcalls[Tmax])(Export*, Fcall*, uchar*);
93 static char Enofid[] = "no such fid";
94 static char Eseekdir[] = "can't seek on a directory";
95 static char Ereaddir[] = "unaligned read of a directory";
96 static int exdebug = 0;
99 sysexport(int fd, Chan **roots, int nroots)
103 fs = smalloc(sizeof(Export));
119 if(fcalls[Tversion] != nil){
124 fmtinstall('F', fcallfmt);
125 fcalls[Tversion] = Exversion;
126 fcalls[Tauth] = Exauth;
127 fcalls[Tattach] = Exattach;
128 fcalls[Twalk] = Exwalk;
129 fcalls[Topen] = Exopen;
130 fcalls[Tcreate] = Excreate;
131 fcalls[Tread] = Exread;
132 fcalls[Twrite] = Exwrite;
133 fcalls[Tclunk] = Exclunk;
134 fcalls[Tremove] = Exremove;
135 fcalls[Tstat] = Exstat;
136 fcalls[Twstat] = Exwstat;
141 exportproc(Export *fs)
150 q = smalloc(sizeof(Exq));
152 n = read9pmsg(fs->io, q->buf, Maxrpc);
153 if(n <= 0 || convM2S(q->buf, n, &q->rpc) != n)
157 print("export %d <- %F\n", getpid(), &q->rpc);
159 if(q->rpc.type == Tflush){
160 exflush(fs, q->rpc.tag, q->rpc.oldtag);
177 exq.nwaiters = n - 1;
180 kproc("exportfs", exslave, nil);
181 rendwakeup(&exq.rwait);
185 fprint(2, "export proc shutting down: %r\n");
191 exflush(Export *fs, int flushtag, int tag)
198 /* hasn't been started? */
201 for(q = exq.head; q != nil; q = q->next){
202 if(q->export == fs && q->rpc.tag == tag){
215 for(q = fs->work; q != nil; q = q->next){
216 if(q->rpc.tag == tag){
231 n = convS2M(&fc, buf, Maxrpc);
233 panic("convS2M error on write");
234 if(write(fs->io, buf, n) != n)
235 panic("mount write");
239 exshutdown(Export *fs)
245 for(q = exq.head; q != nil; q = *last){
256 * cleanly shut down the slaves if this is the last fs around
260 rendwakeup(&exq.rwait);
267 for(q = fs->work; q != nil; q = q->next){
283 if(decref(&fs->r) != 0)
285 for(i = 0; i < Nfidhash; i++){
286 for(f = fs->fid[i]; f != nil; f = n){
302 work = exq.head != nil || !exq.ref;
316 fprint(2, "exslave %d errored out of loop -- heading back in!\n", getpid());
325 rendsleep(&exq.rwait, exwork, nil);
348 * put the job on the work queue before it's
349 * visible as off of the head queue, so it's always
350 * findable for flushes and shutdown
365 print("exslave dispatch %d %F\n", getpid(), &q->rpc);
368 print("exslave err %r\n");
371 if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])
372 err = "bad fcall type";
374 err = (*fcalls[q->rpc.type])(fs, &q->rpc, &q->buf[IOHDRSZ]);
380 q->rpc.type = Rerror;
383 n = convS2M(&q->rpc, q->buf, Maxrpc);
386 print("exslave %d -> %F\n", getpid(), &q->rpc);
392 write(fs->io, q->buf, n);
397 * exflush might set noresponse at this point, but
398 * setting noresponse means don't send a response now;
399 * it's okay that we sent a response already.
402 print("exslave %d written %d\n", getpid(), q->rpc.tag);
406 for(t = fs->work; t != nil; t = t->next){
424 fprint(2, "export slaveshutting down\n");
429 Exmkfid(Export *fs, int fid)
434 nf = mallocz(sizeof(Fid), 1);
439 for(f = fs->fid[h]; f != nil; f = f->next){
441 unlock(&fs->fidlock);
447 nf->next = fs->fid[h];
449 nf->next->last = &nf->next;
450 nf->last = &fs->fid[h];
458 unlock(&fs->fidlock);
463 Exgetfid(Export *fs, int fid)
470 for(f = fs->fid[h]; f; f = f->next){
475 unlock(&fs->fidlock);
479 unlock(&fs->fidlock);
484 Exputfid(Export *fs, Fid *f)
488 if(f->ref == 0 && f->attached == 0){
494 f->next->last = f->last;
495 unlock(&fs->fidlock);
499 unlock(&fs->fidlock);
503 Exversion(Export *fs, Fcall *rpc, uchar *)
506 return "version: message size too small";
507 if(rpc->msize > Maxrpc)
509 if(strncmp(rpc->version, "9P", 2) != 0){
510 rpc->version = "unknown";
514 fs->iounit = rpc->msize - IOHDRSZ;
515 rpc->version = "9P2000";
520 Exauth(Export *, Fcall *, uchar *)
522 return "vnc: authentication not required";
526 Exattach(Export *fs, Fcall *rpc, uchar *)
532 if(rpc->aname != nil)
533 w = strtol(rpc->aname, nil, 10);
534 if(w < 0 || w > fs->nroots)
536 f = Exmkfid(fs, rpc->fid);
544 f->chan = cclone(fs->roots[w]);
546 rpc->qid = f->chan->qid;
552 Exclunk(Export *fs, Fcall *rpc, uchar *)
556 f = Exgetfid(fs, rpc->fid);
565 Exwalk(Export *fs, Fcall *rpc, uchar *)
567 Fid *volatile f, *volatile nf;
573 f = Exgetfid(fs, rpc->fid);
585 * optional clone, but don't attach it until the walk succeeds.
587 if(rpc->fid != rpc->newfid){
588 nf = Exmkfid(fs, rpc->newfid);
594 nf = Exgetfid(fs, rpc->fid);
599 * let the device do the work
602 nwname = rpc->nwname;
603 wq = (*devtab[c->type]->walk)(c, nf->chan, rpc->wname, nwname);
612 for(i = 0; i < wq->nqid; i++)
613 rpc->wqid[i] = wq->qid[i];
614 rpc->nwqid = wq->nqid;
617 * update the channel if everything walked correctly.
619 if(isnew && wq->nqid == nwname){
620 nf->chan = wq->clone;
631 Exopen(Export *fs, Fcall *rpc, uchar *)
637 f = Exgetfid(fs, rpc->fid);
645 c = (*devtab[c->type]->open)(c, rpc->mode);
650 rpc->qid = f->chan->qid;
651 iou = f->chan->iounit;
660 Excreate(Export *fs, Fcall *rpc, uchar *)
666 f = Exgetfid(fs, rpc->fid);
674 (*devtab[c->type]->create)(c, rpc->name, rpc->mode, rpc->perm);
678 rpc->qid = f->chan->qid;
679 iou = f->chan->iounit;
688 Exread(Export *fs, Fcall *rpc, uchar *buf)
694 f = Exgetfid(fs, rpc->fid);
705 rpc->data = (char*)buf;
708 rpc->count = (*devtab[c->type]->read)(c, rpc->data, rpc->count, off);
715 Exwrite(Export *fs, Fcall *rpc, uchar *)
720 f = Exgetfid(fs, rpc->fid);
728 if(c->qid.type & QTDIR)
730 rpc->count = (*devtab[c->type]->write)(c, rpc->data, rpc->count, rpc->offset);
737 Exstat(Export *fs, Fcall *rpc, uchar *buf)
742 f = Exgetfid(fs, rpc->fid);
751 rpc->nstat = (*devtab[c->type]->stat)(c, rpc->stat, Maxrpc);
758 Exwstat(Export *fs, Fcall *rpc, uchar *)
763 f = Exgetfid(fs, rpc->fid);
771 (*devtab[c->type]->wstat)(c, rpc->stat, rpc->nstat);
778 Exremove(Export *fs, Fcall *rpc, uchar *)
783 f = Exgetfid(fs, rpc->fid);
791 (*devtab[c->type]->remove)(c);
795 * chan is already clunked by remove.
796 * however, we need to recover the chan,
797 * and follow sysremove's lead in making to point to root.