summaryrefslogtreecommitdiff
path: root/sys/src/cmd/unix/drawterm/exportfs/exportfs.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/unix/drawterm/exportfs/exportfs.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/unix/drawterm/exportfs/exportfs.c')
-rwxr-xr-xsys/src/cmd/unix/drawterm/exportfs/exportfs.c511
1 files changed, 511 insertions, 0 deletions
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("");
+}
+