diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/unix/drawterm/exportfs |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/unix/drawterm/exportfs')
-rwxr-xr-x | sys/src/cmd/unix/drawterm/exportfs/Makefile | 16 | ||||
-rwxr-xr-x | sys/src/cmd/unix/drawterm/exportfs/exportfs.c | 511 | ||||
-rwxr-xr-x | sys/src/cmd/unix/drawterm/exportfs/exportfs.h | 148 | ||||
-rwxr-xr-x | sys/src/cmd/unix/drawterm/exportfs/exportsrv.c | 676 |
4 files changed, 1351 insertions, 0 deletions
diff --git a/sys/src/cmd/unix/drawterm/exportfs/Makefile b/sys/src/cmd/unix/drawterm/exportfs/Makefile new file mode 100755 index 000000000..e66d8778d --- /dev/null +++ b/sys/src/cmd/unix/drawterm/exportfs/Makefile @@ -0,0 +1,16 @@ +ROOT=.. +include ../Make.config +LIB=libexportfs.a + +OFILES=\ + exportfs.$O\ + exportsrv.$O + +default: $(LIB) +$(LIB): $(OFILES) + $(AR) r $(LIB) $(OFILES) + $(RANLIB) $(LIB) + +%.$O: %.c + $(CC) $(CFLAGS) $*.c + diff --git a/sys/src/cmd/unix/drawterm/exportfs/exportfs.c b/sys/src/cmd/unix/drawterm/exportfs/exportfs.c new file mode 100755 index 000000000..568cdbea1 --- /dev/null +++ b/sys/src/cmd/unix/drawterm/exportfs/exportfs.c @@ -0,0 +1,511 @@ +/* + * exportfs - Export a plan 9 name space across a network + */ +#include <u.h> +#include <libc.h> +#include <fcall.h> +#include <libsec.h> +#include "drawterm.h" +#define Extern +#include "exportfs.h" + +/* #define QIDPATH ((1LL<<48)-1) */ +#define QIDPATH ((((vlong)1)<<48)-1) +vlong newqid = 0; + +void (*fcalls[256])(Fsrpc*); + +/* accounting and debugging counters */ +int filecnt; +int freecnt; +int qidcnt; +int qfreecnt; +int ncollision; +int netfd; + +int +exportfs(int fd, int msgsz) +{ + char buf[ERRMAX], ebuf[ERRMAX]; + Fsrpc *r; + int i, n; + + fcalls[Tversion] = Xversion; + fcalls[Tauth] = Xauth; + fcalls[Tflush] = Xflush; + fcalls[Tattach] = Xattach; + fcalls[Twalk] = Xwalk; + fcalls[Topen] = slave; + fcalls[Tcreate] = Xcreate; + fcalls[Tclunk] = Xclunk; + fcalls[Tread] = slave; + fcalls[Twrite] = slave; + fcalls[Tremove] = Xremove; + fcalls[Tstat] = Xstat; + fcalls[Twstat] = Xwstat; + + srvfd = -1; + netfd = fd; + //dbg = 1; + + strcpy(buf, "this is buf"); + strcpy(ebuf, "this is ebuf"); + DEBUG(DFD, "exportfs: started\n"); + +// rfork(RFNOTEG); + + messagesize = msgsz; + if(messagesize == 0){ + messagesize = iounit(netfd); + if(messagesize == 0) + messagesize = 8192+IOHDRSZ; + } + + Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs); +// for(i=0; i<Nr_workbufs; i++) +// Workq[i].buf = emallocz(messagesize); + fhash = emallocz(sizeof(Fid*)*FHASHSIZE); + + fmtinstall('F', fcallfmt); + + initroot(); + + DEBUG(DFD, "exportfs: %s\n", buf); + + /* + * Start serving file requests from the network + */ + for(;;) { + r = getsbuf(); + if(r == 0) + fatal("Out of service buffers"); + + DEBUG(DFD, "read9p..."); + n = read9pmsg(netfd, r->buf, messagesize); + if(n <= 0) + fatal("eof: n=%d %r", n); + + if(convM2S(r->buf, n, &r->work) == 0){ + iprint("convM2S %d byte message\n", n); + for(i=0; i<n; i++){ + iprint(" %.2ux", r->buf[i]); + if(i%16 == 15) + iprint("\n"); + } + if(i%16) + iprint("\n"); + fatal("convM2S format error"); + } + +if(0) iprint("<- %F\n", &r->work); + DEBUG(DFD, "%F\n", &r->work); + (fcalls[r->work.type])(r); + } +} + +void +reply(Fcall *r, Fcall *t, char *err) +{ + uchar *data; + int m, n; + + t->tag = r->tag; + t->fid = r->fid; + if(err) { + t->type = Rerror; + t->ename = err; + } + else + t->type = r->type + 1; + +if(0) iprint("-> %F\n", t); + DEBUG(DFD, "\t%F\n", t); + + data = malloc(messagesize); /* not mallocz; no need to clear */ + if(data == nil) + fatal(Enomem); + n = convS2M(t, data, messagesize); + if((m=write(netfd, data, n))!=n){ + iprint("wrote %d got %d (%r)\n", n, m); + fatal("write"); + } + free(data); +} + +Fid * +getfid(int nr) +{ + Fid *f; + + for(f = fidhash(nr); f; f = f->next) + if(f->nr == nr) + return f; + + return 0; +} + +int +freefid(int nr) +{ + Fid *f, **l; + char buf[128]; + + l = &fidhash(nr); + for(f = *l; f; f = f->next) { + if(f->nr == nr) { + if(f->mid) { + sprint(buf, "/mnt/exportfs/%d", f->mid); + unmount(0, buf); + psmap[f->mid] = 0; + } + if(f->f) { + freefile(f->f); + f->f = nil; + } + *l = f->next; + f->next = fidfree; + fidfree = f; + return 1; + } + l = &f->next; + } + + return 0; +} + +Fid * +newfid(int nr) +{ + Fid *new, **l; + int i; + + l = &fidhash(nr); + for(new = *l; new; new = new->next) + if(new->nr == nr) + return 0; + + if(fidfree == 0) { + fidfree = emallocz(sizeof(Fid) * Fidchunk); + + for(i = 0; i < Fidchunk-1; i++) + fidfree[i].next = &fidfree[i+1]; + + fidfree[Fidchunk-1].next = 0; + } + + new = fidfree; + fidfree = new->next; + + memset(new, 0, sizeof(Fid)); + new->next = *l; + *l = new; + new->nr = nr; + new->fid = -1; + new->mid = 0; + + return new; +} + +Fsrpc * +getsbuf(void) +{ + static int ap; + int look, rounds; + Fsrpc *wb; + int small_instead_of_fast = 1; + + if(small_instead_of_fast) + ap = 0; /* so we always start looking at the beginning and reuse buffers */ + + for(rounds = 0; rounds < 10; rounds++) { + for(look = 0; look < Nr_workbufs; look++) { + if(++ap == Nr_workbufs) + ap = 0; + if(Workq[ap].busy == 0) + break; + } + + if(look == Nr_workbufs){ + sleep(10 * rounds); + continue; + } + + wb = &Workq[ap]; + wb->pid = 0; + wb->canint = 0; + wb->flushtag = NOTAG; + wb->busy = 1; + if(wb->buf == nil) /* allocate buffers dynamically to keep size down */ + wb->buf = emallocz(messagesize); + return wb; + } + fatal("No more work buffers"); + return nil; +} + +void +freefile(File *f) +{ + File *parent, *child; + +Loop: + f->ref--; + if(f->ref > 0) + return; + freecnt++; + if(f->ref < 0) abort(); + DEBUG(DFD, "free %s\n", f->name); + /* delete from parent */ + parent = f->parent; + if(parent->child == f) + parent->child = f->childlist; + else{ + for(child=parent->child; child->childlist!=f; child=child->childlist) + if(child->childlist == nil) + fatal("bad child list"); + child->childlist = f->childlist; + } + freeqid(f->qidt); + free(f->name); + f->name = nil; + free(f); + f = parent; + if(f != nil) + goto Loop; +} + +File * +file(File *parent, char *name) +{ + Dir *dir; + char *path; + File *f; + + DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name); + + path = makepath(parent, name); + dir = dirstat(path); + free(path); + if(dir == nil) + return nil; + + for(f = parent->child; f; f = f->childlist) + if(strcmp(name, f->name) == 0) + break; + + if(f == nil){ + f = emallocz(sizeof(File)); + f->name = estrdup(name); + + f->parent = parent; + f->childlist = parent->child; + parent->child = f; + parent->ref++; + f->ref = 0; + filecnt++; + } + f->ref++; + f->qid.type = dir->qid.type; + f->qid.vers = dir->qid.vers; + f->qidt = uniqueqid(dir); + f->qid.path = f->qidt->uniqpath; + + f->inval = 0; + + free(dir); + + return f; +} + +void +initroot(void) +{ + Dir *dir; + + root = emallocz(sizeof(File)); + root->name = estrdup("."); + + dir = dirstat(root->name); + if(dir == nil) + fatal("root stat"); + + root->ref = 1; + root->qid.vers = dir->qid.vers; + root->qidt = uniqueqid(dir); + root->qid.path = root->qidt->uniqpath; + root->qid.type = QTDIR; + free(dir); + + psmpt = emallocz(sizeof(File)); + psmpt->name = estrdup("/"); + + dir = dirstat(psmpt->name); + if(dir == nil) + return; + + psmpt->ref = 1; + psmpt->qid.vers = dir->qid.vers; + psmpt->qidt = uniqueqid(dir); + psmpt->qid.path = psmpt->qidt->uniqpath; + free(dir); + + psmpt = file(psmpt, "mnt"); + if(psmpt == 0) + return; + psmpt = file(psmpt, "exportfs"); +} + +char* +makepath(File *p, char *name) +{ + int i, n; + char *c, *s, *path, *seg[256]; + + seg[0] = name; + n = strlen(name)+2; + for(i = 1; i < 256 && p; i++, p = p->parent){ + seg[i] = p->name; + n += strlen(p->name)+1; + } + path = malloc(n); + if(path == nil) + fatal("out of memory"); + s = path; + + while(i--) { + for(c = seg[i]; *c; c++) + *s++ = *c; + *s++ = '/'; + } + while(s[-1] == '/') + s--; + *s = '\0'; + + return path; +} + +int +qidhash(vlong path) +{ + int h, n; + + h = 0; + for(n=0; n<64; n+=Nqidbits){ + h ^= path; + path >>= Nqidbits; + } + return h & (Nqidtab-1); +} + +void +freeqid(Qidtab *q) +{ + ulong h; + Qidtab *l; + + q->ref--; + if(q->ref > 0) + return; + qfreecnt++; + h = qidhash(q->path); + if(qidtab[h] == q) + qidtab[h] = q->next; + else{ + for(l=qidtab[h]; l->next!=q; l=l->next) + if(l->next == nil) + fatal("bad qid list"); + l->next = q->next; + } + free(q); +} + +Qidtab* +qidlookup(Dir *d) +{ + ulong h; + Qidtab *q; + + h = qidhash(d->qid.path); + for(q=qidtab[h]; q!=nil; q=q->next) + if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path) + return q; + return nil; +} + +int +qidexists(vlong path) +{ + int h; + Qidtab *q; + + for(h=0; h<Nqidtab; h++) + for(q=qidtab[h]; q!=nil; q=q->next) + if(q->uniqpath == path) + return 1; + return 0; +} + +Qidtab* +uniqueqid(Dir *d) +{ + ulong h; + vlong path; + Qidtab *q; + + q = qidlookup(d); + if(q != nil){ + q->ref++; + return q; + } + path = d->qid.path; + while(qidexists(path)){ + DEBUG(DFD, "collision on %s\n", d->name); + /* collision: find a new one */ + ncollision++; + path &= QIDPATH; + ++newqid; + if(newqid >= (1<<16)){ + DEBUG(DFD, "collision wraparound\n"); + newqid = 1; + } + path |= newqid<<48; + DEBUG(DFD, "assign qid %.16llux\n", path); + } + q = mallocz(sizeof(Qidtab), 1); + if(q == nil) + fatal("no memory for qid table"); + qidcnt++; + q->ref = 1; + q->type = d->type; + q->dev = d->dev; + q->path = d->qid.path; + q->uniqpath = path; + h = qidhash(d->qid.path); + q->next = qidtab[h]; + qidtab[h] = q; + return q; +} + +void +fatal(char *s, ...) +{ + char buf[ERRMAX]; + va_list arg; + + if (s) { + va_start(arg, s); + vsnprint(buf, ERRMAX, s, arg); + va_end(arg); + } + + /* Clear away the slave children */ +// for(m = Proclist; m; m = m->next) +// postnote(PNPROC, m->pid, "kill"); + + DEBUG(DFD, "%s\n", buf); + if (s) + sysfatal(buf); + else + sysfatal(""); +} + diff --git a/sys/src/cmd/unix/drawterm/exportfs/exportfs.h b/sys/src/cmd/unix/drawterm/exportfs/exportfs.h new file mode 100755 index 000000000..3231573a9 --- /dev/null +++ b/sys/src/cmd/unix/drawterm/exportfs/exportfs.h @@ -0,0 +1,148 @@ +/* + * exportfs.h - definitions for exporting file server + */ + +#define DEBUG if(!dbg){}else fprint +#define DFD 2 +#define fidhash(s) fhash[s%FHASHSIZE] + +#define Proc Exproc + + +typedef struct Fsrpc Fsrpc; +typedef struct Fid Fid; +typedef struct File File; +typedef struct Proc Proc; +typedef struct Qidtab Qidtab; + +struct Fsrpc +{ + int busy; /* Work buffer has pending rpc to service */ + int pid; /* Pid of slave process executing the rpc */ + int canint; /* Interrupt gate */ + int flushtag; /* Tag on which to reply to flush */ + Fcall work; /* Plan 9 incoming Fcall */ + uchar *buf; /* Data buffer */ +}; + +struct Fid +{ + int fid; /* system fd for i/o */ + File *f; /* File attached to this fid */ + int mode; + int nr; /* fid number */ + int mid; /* Mount id */ + Fid *next; /* hash link */ +}; + +struct File +{ + char *name; + int ref; + Qid qid; + Qidtab *qidt; + int inval; + File *parent; + File *child; + File *childlist; +}; + +struct Proc +{ + int pid; + int busy; + Proc *next; +}; + +struct Qidtab +{ + int ref; + int type; + int dev; + vlong path; + vlong uniqpath; + Qidtab *next; +}; + +enum +{ + MAXPROC = 50, + FHASHSIZE = 64, + Nr_workbufs = 50, + Fidchunk = 1000, + Npsmpt = 32, + Nqidbits = 5, + Nqidtab = (1<<Nqidbits), +}; + +#define Enomem Exenomem +#define Ebadfix Exebadfid +#define Enotdir Exenotdir +#define Edupfid Exedupfid +#define Eopen Exeopen +#define Exmnt Exexmnt +#define Emip Exemip +#define Enopsmt Exenopsmt + +extern char Ebadfid[]; +extern char Enotdir[]; +extern char Edupfid[]; +extern char Eopen[]; +extern char Exmnt[]; +extern char Enomem[]; +extern char Emip[]; +extern char Enopsmt[]; + +Extern Fsrpc *Workq; +Extern int dbg; +Extern File *root; +Extern File *psmpt; +Extern Fid **fhash; +Extern Fid *fidfree; +Extern Proc *Proclist; +Extern char psmap[Npsmpt]; +Extern Qidtab *qidtab[Nqidtab]; +Extern ulong messagesize; +Extern int srvfd; + +/* File system protocol service procedures */ +void Xattach(Fsrpc*); +void Xauth(Fsrpc*); +void Xclunk(Fsrpc*); +void Xcreate(Fsrpc*); +void Xflush(Fsrpc*); +void Xnop(Fsrpc*); +void Xremove(Fsrpc*); +void Xstat(Fsrpc*); +void Xversion(Fsrpc*); +void Xwalk(Fsrpc*); +void Xwstat(Fsrpc*); +void slave(Fsrpc*); + +void reply(Fcall*, Fcall*, char*); +Fid *getfid(int); +int freefid(int); +Fid *newfid(int); +Fsrpc *getsbuf(void); +void initroot(void); +void fatal(char*, ...); +char* makepath(File*, char*); +File *file(File*, char*); +void freefile(File*); +void slaveopen(Fsrpc*); +void slaveread(Fsrpc*); +void slavewrite(Fsrpc*); +void blockingslave(void*); +void reopen(Fid *f); +void noteproc(int, char*); +void flushaction(void*, char*); +void pushfcall(char*); +Qidtab* uniqueqid(Dir*); +void freeqid(Qidtab*); +char* estrdup(char*); +void* emallocz(uint); +int readmessage(int, char*, int); + +#define notify(x) +#define noted(x) +#define exits(x) diff --git a/sys/src/cmd/unix/drawterm/exportfs/exportsrv.c b/sys/src/cmd/unix/drawterm/exportfs/exportsrv.c new file mode 100755 index 000000000..dabb6a0e8 --- /dev/null +++ b/sys/src/cmd/unix/drawterm/exportfs/exportsrv.c @@ -0,0 +1,676 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> +#define Extern extern +#include "exportfs.h" + +char Ebadfid[] = "Bad fid"; +char Enotdir[] = "Not a directory"; +char Edupfid[] = "Fid already in use"; +char Eopen[] = "Fid already opened"; +char Exmnt[] = "Cannot .. past mount point"; +char Emip[] = "Mount in progress"; +char Enopsmt[] = "Out of pseudo mount points"; +char Enomem[] = "No memory"; +char Eversion[] = "Bad 9P2000 version"; + +int iounit(int x) +{ + return 8192+IOHDRSZ; +} + +void* +emallocz(ulong n) +{ + void *v; + + v = mallocz(n, 1); + if(v == nil) + panic("out of memory"); + return v; +} + + +void +Xversion(Fsrpc *t) +{ + Fcall rhdr; + + if(t->work.msize > messagesize) + t->work.msize = messagesize; + messagesize = t->work.msize; + if(strncmp(t->work.version, "9P2000", 6) != 0){ + reply(&t->work, &rhdr, Eversion); + return; + } + rhdr.version = "9P2000"; + rhdr.msize = t->work.msize; + reply(&t->work, &rhdr, 0); + t->busy = 0; +} + +void +Xauth(Fsrpc *t) +{ + Fcall rhdr; + + reply(&t->work, &rhdr, "exportfs: authentication not required"); + t->busy = 0; +} + +void +Xflush(Fsrpc *t) +{ + Fsrpc *w, *e; + Fcall rhdr; + + e = &Workq[Nr_workbufs]; + + for(w = Workq; w < e; w++) { + if(w->work.tag == t->work.oldtag) { + DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint); + if(w->busy && w->pid) { + w->flushtag = t->work.tag; + DEBUG(DFD, "\tset flushtag %d\n", t->work.tag); + // if(w->canint) + // postnote(PNPROC, w->pid, "flush"); + t->busy = 0; + return; + } + } + } + + reply(&t->work, &rhdr, 0); + DEBUG(DFD, "\tflush reply\n"); + t->busy = 0; +} + +void +Xattach(Fsrpc *t) +{ + Fcall rhdr; + Fid *f; + + f = newfid(t->work.fid); + if(f == 0) { + reply(&t->work, &rhdr, Ebadfid); + t->busy = 0; + return; + } + + if(srvfd >= 0){ +/* + if(psmpt == 0){ + Nomount: + reply(&t->work, &rhdr, Enopsmt); + t->busy = 0; + freefid(t->work.fid); + return; + } + for(i=0; i<Npsmpt; i++) + if(psmap[i] == 0) + break; + if(i >= Npsmpt) + goto Nomount; + sprint(buf, "%d", i); + f->f = file(psmpt, buf); + if(f->f == nil) + goto Nomount; + sprint(buf, "/mnt/exportfs/%d", i); + nfd = dup(srvfd, -1); + if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){ + errstr(buf, sizeof buf); + reply(&t->work, &rhdr, buf); + t->busy = 0; + freefid(t->work.fid); + close(nfd); + return; + } + psmap[i] = 1; + f->mid = i; +*/ + }else{ + f->f = root; + f->f->ref++; + } + + rhdr.qid = f->f->qid; + reply(&t->work, &rhdr, 0); + t->busy = 0; +} + +Fid* +clonefid(Fid *f, int new) +{ + Fid *n; + + n = newfid(new); + if(n == 0) { + n = getfid(new); + if(n == 0) + fatal("inconsistent fids"); + if(n->fid >= 0) + close(n->fid); + freefid(new); + n = newfid(new); + if(n == 0) + fatal("inconsistent fids2"); + } + n->f = f->f; + n->f->ref++; + return n; +} + +void +Xwalk(Fsrpc *t) +{ + char err[ERRMAX], *e; + Fcall rhdr; + Fid *f, *nf; + File *wf; + int i; + + f = getfid(t->work.fid); + if(f == 0) { + reply(&t->work, &rhdr, Ebadfid); + t->busy = 0; + return; + } + + nf = nil; + if(t->work.newfid != t->work.fid){ + nf = clonefid(f, t->work.newfid); + f = nf; + } + + rhdr.nwqid = 0; + e = nil; + for(i=0; i<t->work.nwname; i++){ + if(i == MAXWELEM){ + e = "Too many path elements"; + break; + } + + if(strcmp(t->work.wname[i], "..") == 0) { + if(f->f->parent == nil) { + e = Exmnt; + break; + } + wf = f->f->parent; + wf->ref++; + goto Accept; + } + + wf = file(f->f, t->work.wname[i]); + if(wf == 0){ + errstr(err, sizeof err); + e = err; + break; + } + Accept: + freefile(f->f); + rhdr.wqid[rhdr.nwqid++] = wf->qid; + f->f = wf; + continue; + } + + if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname)) + freefid(t->work.newfid); + if(rhdr.nwqid > 0) + e = nil; + reply(&t->work, &rhdr, e); + t->busy = 0; +} + +void +Xclunk(Fsrpc *t) +{ + Fcall rhdr; + Fid *f; + + f = getfid(t->work.fid); + if(f == 0) { + reply(&t->work, &rhdr, Ebadfid); + t->busy = 0; + return; + } + + if(f->fid >= 0) + close(f->fid); + + freefid(t->work.fid); + reply(&t->work, &rhdr, 0); + t->busy = 0; +} + +void +Xstat(Fsrpc *t) +{ + char err[ERRMAX], *path; + Fcall rhdr; + Fid *f; + Dir *d; + int s; + uchar *statbuf; + + f = getfid(t->work.fid); + if(f == 0) { + reply(&t->work, &rhdr, Ebadfid); + t->busy = 0; + return; + } + if(f->fid >= 0) + d = dirfstat(f->fid); + else { + path = makepath(f->f, ""); + d = dirstat(path); + free(path); + } + + if(d == nil) { + errstr(err, sizeof err); + reply(&t->work, &rhdr, err); + t->busy = 0; + return; + } + + d->qid.path = f->f->qidt->uniqpath; + s = sizeD2M(d); + statbuf = emallocz(s); + s = convD2M(d, statbuf, s); + free(d); + rhdr.nstat = s; + rhdr.stat = statbuf; + reply(&t->work, &rhdr, 0); + free(statbuf); + t->busy = 0; +} + +static int +getiounit(int fd) +{ + int n; + + n = iounit(fd); + if(n > messagesize-IOHDRSZ) + n = messagesize-IOHDRSZ; + return n; +} + +void +Xcreate(Fsrpc *t) +{ + char err[ERRMAX], *path; + Fcall rhdr; + Fid *f; + File *nf; + + f = getfid(t->work.fid); + if(f == 0) { + reply(&t->work, &rhdr, Ebadfid); + t->busy = 0; + return; + } + + + path = makepath(f->f, t->work.name); + f->fid = create(path, t->work.mode, t->work.perm); + free(path); + if(f->fid < 0) { + errstr(err, sizeof err); + reply(&t->work, &rhdr, err); + t->busy = 0; + return; + } + + nf = file(f->f, t->work.name); + if(nf == 0) { + errstr(err, sizeof err); + reply(&t->work, &rhdr, err); + t->busy = 0; + return; + } + + f->mode = t->work.mode; + freefile(f->f); + f->f = nf; + rhdr.qid = f->f->qid; + rhdr.iounit = getiounit(f->fid); + reply(&t->work, &rhdr, 0); + t->busy = 0; +} + +void +Xremove(Fsrpc *t) +{ + char err[ERRMAX], *path; + Fcall rhdr; + Fid *f; + + f = getfid(t->work.fid); + if(f == 0) { + reply(&t->work, &rhdr, Ebadfid); + t->busy = 0; + return; + } + + path = makepath(f->f, ""); + DEBUG(DFD, "\tremove: %s\n", path); + if(remove(path) < 0) { + free(path); + errstr(err, sizeof err); + reply(&t->work, &rhdr, err); + t->busy = 0; + return; + } + free(path); + + f->f->inval = 1; + if(f->fid >= 0) + close(f->fid); + freefid(t->work.fid); + + reply(&t->work, &rhdr, 0); + t->busy = 0; +} + +void +Xwstat(Fsrpc *t) +{ + char err[ERRMAX], *path; + Fcall rhdr; + Fid *f; + int s; + char *strings; + Dir d; + + f = getfid(t->work.fid); + if(f == 0) { + reply(&t->work, &rhdr, Ebadfid); + t->busy = 0; + return; + } + strings = emallocz(t->work.nstat); /* ample */ + if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){ + rerrstr(err, sizeof err); + reply(&t->work, &rhdr, err); + t->busy = 0; + free(strings); + return; + } + + if(f->fid >= 0) + s = dirfwstat(f->fid, &d); + else { + path = makepath(f->f, ""); + s = dirwstat(path, &d); + free(path); + } + if(s < 0) { + rerrstr(err, sizeof err); + reply(&t->work, &rhdr, err); + } + else { + /* wstat may really be rename */ + if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){ + free(f->f->name); + f->f->name = estrdup(d.name); + } + reply(&t->work, &rhdr, 0); + } + free(strings); + t->busy = 0; +} + +void +slave(Fsrpc *f) +{ + Proc *p; + int pid; + static int nproc; + + for(;;) { + for(p = Proclist; p; p = p->next) { + if(p->busy == 0) { + f->pid = p->pid; + p->busy = 1; + pid = (uintptr)rendezvous((void*)(uintptr)p->pid, f); + if(pid != p->pid) + fatal("rendezvous sync fail"); + return; + } + } + + if(++nproc > MAXPROC) + fatal("too many procs"); + + pid = kproc("slave", blockingslave, nil); + DEBUG(DFD, "slave pid %d\n", pid); + if(pid == -1) + fatal("kproc"); + + p = malloc(sizeof(Proc)); + if(p == 0) + fatal("out of memory"); + + p->busy = 0; + p->pid = pid; + p->next = Proclist; + Proclist = p; + +DEBUG(DFD, "parent %d rendez\n", pid); + rendezvous((void*)(uintptr)pid, p); +DEBUG(DFD, "parent %d went\n", pid); + } +} + +void +blockingslave(void *x) +{ + Fsrpc *p; + Fcall rhdr; + Proc *m; + int pid; + + USED(x); + + notify(flushaction); + + pid = getpid(); + +DEBUG(DFD, "blockingslave %d rendez\n", pid); + m = (Proc*)rendezvous((void*)(uintptr)pid, 0); +DEBUG(DFD, "blockingslave %d rendez got %p\n", pid, m); + + for(;;) { + p = rendezvous((void*)(uintptr)pid, (void*)(uintptr)pid); + if((uintptr)p == ~(uintptr)0) /* Interrupted */ + continue; + + DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid); + if(p->flushtag != NOTAG) + goto flushme; + + switch(p->work.type) { + case Tread: + slaveread(p); + break; + + case Twrite: + slavewrite(p); + break; + + case Topen: + slaveopen(p); + break; + + default: + reply(&p->work, &rhdr, "exportfs: slave type error"); + } + if(p->flushtag != NOTAG) { +flushme: + p->work.type = Tflush; + p->work.tag = p->flushtag; + reply(&p->work, &rhdr, 0); + } + p->busy = 0; + m->busy = 0; + } +} + +int +openmount(int sfd) +{ + werrstr("openmount not implemented"); + return -1; +} + +void +slaveopen(Fsrpc *p) +{ + char err[ERRMAX], *path; + Fcall *work, rhdr; + Fid *f; + Dir *d; + + work = &p->work; + + f = getfid(work->fid); + if(f == 0) { + reply(work, &rhdr, Ebadfid); + return; + } + if(f->fid >= 0) { + close(f->fid); + f->fid = -1; + } + + path = makepath(f->f, ""); + DEBUG(DFD, "\topen: %s %d\n", path, work->mode); + + p->canint = 1; + if(p->flushtag != NOTAG){ + free(path); + return; + } + /* There is a race here I ignore because there are no locks */ + f->fid = open(path, work->mode); + free(path); + p->canint = 0; + if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) { + Error: + errstr(err, sizeof err); + reply(work, &rhdr, err); + return; + } + f->f->qid = d->qid; + free(d); + if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */ + f->fid = openmount(f->fid); + if(f->fid < 0) + goto Error; + } + + DEBUG(DFD, "\topen: fd %d\n", f->fid); + f->mode = work->mode; + rhdr.iounit = getiounit(f->fid); + rhdr.qid = f->f->qid; + reply(work, &rhdr, 0); +} + +void +slaveread(Fsrpc *p) +{ + Fid *f; + int n, r; + Fcall *work, rhdr; + char *data, err[ERRMAX]; + + work = &p->work; + + f = getfid(work->fid); + if(f == 0) { + reply(work, &rhdr, Ebadfid); + return; + } + + n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count; + p->canint = 1; + if(p->flushtag != NOTAG) + return; + data = malloc(n); + if(data == nil) + fatal(Enomem); + + /* can't just call pread, since directories must update the offset */ + r = pread(f->fid, data, n, work->offset); + p->canint = 0; + if(r < 0) { + free(data); + errstr(err, sizeof err); + reply(work, &rhdr, err); + return; + } + + DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r); + + rhdr.data = data; + rhdr.count = r; + reply(work, &rhdr, 0); + free(data); +} + +void +slavewrite(Fsrpc *p) +{ + char err[ERRMAX]; + Fcall *work, rhdr; + Fid *f; + int n; + + work = &p->work; + + f = getfid(work->fid); + if(f == 0) { + reply(work, &rhdr, Ebadfid); + return; + } + + n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count; + p->canint = 1; + if(p->flushtag != NOTAG) + return; + n = pwrite(f->fid, work->data, n, work->offset); + p->canint = 0; + if(n < 0) { + errstr(err, sizeof err); + reply(work, &rhdr, err); + return; + } + + DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid); + + rhdr.count = n; + reply(work, &rhdr, 0); +} + +void +reopen(Fid *f) +{ + USED(f); + fatal("reopen"); +} + +void +flushaction(void *a, char *cause) +{ + USED(a); + if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) { + fprint(2, "exportsrv: note: %s\n", cause); + exits("noted"); + } + if(strncmp(cause, "kill", 4) == 0) + noted(NDFLT); + + noted(NCONT); +} |