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);
186 fprint(2, "export proc shutting down: %r\n");
192 exflush(Export *fs, int flushtag, int tag)
199 /* hasn't been started? */
202 for(q = exq.head; q != nil; q = q->next){
203 if(q->export == fs && q->rpc.tag == tag){
216 for(q = fs->work; q != nil; q = q->next){
217 if(q->rpc.tag == tag){
232 n = convS2M(&fc, buf, Maxrpc);
234 panic("convS2M error on write");
235 if(write(fs->io, buf, n) != n)
236 panic("mount write");
240 exshutdown(Export *fs)
246 for(q = exq.head; q != nil; q = *last){
257 * cleanly shut down the slaves if this is the last fs around
261 rendwakeup(&exq.rwait);
268 for(q = fs->work; q != nil; q = q->next){
284 if(decref(&fs->r) != 0)
286 for(i = 0; i < Nfidhash; i++){
287 for(f = fs->fid[i]; f != nil; f = n){
303 work = exq.head != nil || !exq.ref;
317 fprint(2, "exslave %d errored out of loop -- heading back in!\n", getpid());
326 rendsleep(&exq.rwait, exwork, nil);
349 * put the job on the work queue before it's
350 * visible as off of the head queue, so it's always
351 * findable for flushes and shutdown
366 print("exslave dispatch %d %F\n", getpid(), &q->rpc);
369 print("exslave err %r\n");
372 if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])
373 err = "bad fcall type";
375 err = (*fcalls[q->rpc.type])(fs, &q->rpc, &q->buf[IOHDRSZ]);
381 q->rpc.type = Rerror;
384 n = convS2M(&q->rpc, q->buf, Maxrpc);
387 print("exslave %d -> %F\n", getpid(), &q->rpc);
393 write(fs->io, q->buf, n);
398 * exflush might set noresponse at this point, but
399 * setting noresponse means don't send a response now;
400 * it's okay that we sent a response already.
403 print("exslave %d written %d\n", getpid(), q->rpc.tag);
407 for(t = fs->work; t != nil; t = t->next){
425 fprint(2, "export slaveshutting down\n");
430 Exmkfid(Export *fs, int fid)
435 nf = mallocz(sizeof(Fid), 1);
440 for(f = fs->fid[h]; f != nil; f = f->next){
442 unlock(&fs->fidlock);
448 nf->next = fs->fid[h];
450 nf->next->last = &nf->next;
451 nf->last = &fs->fid[h];
459 unlock(&fs->fidlock);
464 Exgetfid(Export *fs, int fid)
471 for(f = fs->fid[h]; f; f = f->next){
476 unlock(&fs->fidlock);
480 unlock(&fs->fidlock);
485 Exputfid(Export *fs, Fid *f)
489 if(f->ref == 0 && f->attached == 0){
495 f->next->last = f->last;
496 unlock(&fs->fidlock);
500 unlock(&fs->fidlock);
504 Exversion(Export *fs, Fcall *rpc, uchar *)
506 if(rpc->msize > Maxrpc)
508 if(strncmp(rpc->version, "9P", 2) != 0){
509 rpc->version = "unknown";
513 fs->iounit = rpc->msize - IOHDRSZ;
514 rpc->version = "9P2000";
519 Exauth(Export *, Fcall *, uchar *)
521 return "vnc: authentication not required";
525 Exattach(Export *fs, Fcall *rpc, uchar *)
531 if(rpc->aname != nil)
532 w = strtol(rpc->aname, nil, 10);
533 if(w < 0 || w > fs->nroots)
535 f = Exmkfid(fs, rpc->fid);
543 f->chan = cclone(fs->roots[w]);
545 rpc->qid = f->chan->qid;
551 Exclunk(Export *fs, Fcall *rpc, uchar *)
555 f = Exgetfid(fs, rpc->fid);
564 Exwalk(Export *fs, Fcall *rpc, uchar *)
566 Fid *volatile f, *volatile nf;
572 f = Exgetfid(fs, rpc->fid);
584 * optional clone, but don't attach it until the walk succeeds.
586 if(rpc->fid != rpc->newfid){
587 nf = Exmkfid(fs, rpc->newfid);
593 nf = Exgetfid(fs, rpc->fid);
598 * let the device do the work
601 nwname = rpc->nwname;
602 wq = (*devtab[c->type]->walk)(c, nf->chan, rpc->wname, nwname);
611 for(i = 0; i < wq->nqid; i++)
612 rpc->wqid[i] = wq->qid[i];
613 rpc->nwqid = wq->nqid;
616 * update the channel if everything walked correctly.
618 if(isnew && wq->nqid == nwname){
619 nf->chan = wq->clone;
630 Exopen(Export *fs, Fcall *rpc, uchar *)
636 f = Exgetfid(fs, rpc->fid);
644 c = (*devtab[c->type]->open)(c, rpc->mode);
649 rpc->qid = f->chan->qid;
650 iou = f->chan->iounit;
659 Excreate(Export *fs, Fcall *rpc, uchar *)
665 f = Exgetfid(fs, rpc->fid);
673 (*devtab[c->type]->create)(c, rpc->name, rpc->mode, rpc->perm);
677 rpc->qid = f->chan->qid;
678 iou = f->chan->iounit;
687 Exread(Export *fs, Fcall *rpc, uchar *buf)
693 f = Exgetfid(fs, rpc->fid);
704 rpc->data = (char*)buf;
707 rpc->count = (*devtab[c->type]->read)(c, rpc->data, rpc->count, off);
714 Exwrite(Export *fs, Fcall *rpc, uchar *)
719 f = Exgetfid(fs, rpc->fid);
727 if(c->qid.type & QTDIR)
729 rpc->count = (*devtab[c->type]->write)(c, rpc->data, rpc->count, rpc->offset);
736 Exstat(Export *fs, Fcall *rpc, uchar *buf)
741 f = Exgetfid(fs, rpc->fid);
750 rpc->nstat = (*devtab[c->type]->stat)(c, rpc->stat, Maxrpc);
757 Exwstat(Export *fs, Fcall *rpc, uchar *)
762 f = Exgetfid(fs, rpc->fid);
770 (*devtab[c->type]->wstat)(c, rpc->stat, rpc->nstat);
777 Exremove(Export *fs, Fcall *rpc, uchar *)
782 f = Exgetfid(fs, rpc->fid);
790 (*devtab[c->type]->remove)(c);
794 * chan is already clunked by remove.
795 * however, we need to recover the chan,
796 * and follow sysremove's lead in making to point to root.