ref: de0baba0ab52f9279212233558bbb1ff67e5106c
parent: 7fee327ee530409dee0d36cb258927934ba97aff
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Aug 18 09:58:49 EDT 2025
exportfs: backport updated exportfs from 9front This has some improvements for handling the processes and handles flushes properly.
--- a/exportfs/Makefile
+++ b/exportfs/Makefile
@@ -2,9 +2,12 @@
include ../Make.config
LIB=libexportfs.a
+HFILES=exportfs.h
+
OFILES=\
exportfs.$O\
- exportsrv.$O
+ exportsrv.$O\
+ io.$O\
default: $(LIB)
$(LIB): $(OFILES)
--- a/exportfs/exportfs.c
+++ b/exportfs/exportfs.c
@@ -6,57 +6,18 @@
#include <fcall.h>
#include <libsec.h>
#include "drawterm.h"
-#define Extern
+#define Extern extern
#include "exportfs.h"
-#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[2];
-
int
exportfs(int rfd, int wfd)
{
- char buf[ERRMAX], ebuf[ERRMAX];
- Fsrpc *r;
- int i, n;
+ DEBUG("exportfs: started\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[0] = rfd;
- netfd[1] = wfd;
-
- strcpy(buf, "this is buf");
- strcpy(ebuf, "this is ebuf");
- DEBUG(DFD, "exportfs: started\n");
-
messagesize = iounit(rfd);
if(messagesize == 0)
messagesize = IOUNIT+IOHDRSZ;
- Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs);
fhash = emallocz(sizeof(Fid*)*FHASHSIZE);
fmtinstall('F', fcallfmt);
@@ -63,443 +24,7 @@
initroot();
- DEBUG(DFD, "exportfs: %s\n", buf);
+ io(rfd, wfd);
- /*
- * Start serving file requests from the network
- */
- for(;;) {
- r = getsbuf();
- if(r == 0)
- fatal("Out of service buffers");
-
- DEBUG(DFD, "read9p...");
- n = read9pmsg(netfd[0], r->buf, messagesize);
- if(n <= 0)
- fatal(nil);
-
- 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[1], 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->kp = nil;
- 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;
- Proc *m;
-
- if (s != nil) {
- va_start(arg, s);
- vsnprint(buf, ERRMAX, s, arg);
- va_end(arg);
- }
-
- /* Clear away the slave children */
- for(m = Proclist; m; m = m->next)
- kprocint(m->kp);
-
- if (s != nil) {
- DEBUG(DFD, "%s\n", buf);
- sysfatal("%s", buf);
- } else
- exits(nil);
-}
-
--- a/exportfs/exportfs.h
+++ b/exportfs/exportfs.h
@@ -2,13 +2,11 @@
* exportfs.h - definitions for exporting file server
*/
-#define DEBUG if(!dbg){}else fprint
-#define DFD 2
+#define DEBUG(...)
#define fidhash(s) fhash[s%FHASHSIZE]
#define Proc Exproc
-
typedef struct Fsrpc Fsrpc;
typedef struct Fid Fid;
typedef struct File File;
@@ -17,12 +15,10 @@
struct Fsrpc
{
- int busy; /* Work buffer has pending rpc to service */
- void* kp; /* slave process executing the rpc */
- int canint; /* Interrupt gate */
+ Fsrpc *next; /* freelist */
int flushtag; /* Tag on which to reply to flush */
- Fcall work; /* Plan 9 incoming Fcall */
- uchar *buf; /* Data buffer */
+ Fcall work; /* Plan 9 incoming Fcall */
+ uchar buf[]; /* Data buffer */
};
struct Fid
@@ -33,6 +29,13 @@
int nr; /* fid number */
int mid; /* Mount id */
Fid *next; /* hash link */
+
+ /* for preaddir -- ARRGH! */
+ Dir *dir; /* buffer for reading directories */
+ int ndir; /* number of entries in dir */
+ int cdir; /* number of consumed entries in dir */
+ int gdir; /* glue index */
+ vlong offset; /* offset in virtual directory */
};
struct File
@@ -49,9 +52,10 @@
struct Proc
{
- void *kp;
- int busy;
+ Lock lock;
+ Fsrpc *busy;
Proc *next;
+ void *kp;
};
struct Qidtab
@@ -66,9 +70,7 @@
enum
{
- MAXPROC = 50,
FHASHSIZE = 64,
- Nr_workbufs = 50,
Fidchunk = 1000,
Npsmpt = 32,
Nqidbits = 5,
@@ -76,34 +78,26 @@
};
#define Enomem Exenomem
-#define Ebadfix Exebadfid
+#define Ebadfid Exebadfid
#define Enotdir Exenotdir
#define Edupfid Exedupfid
#define Eopen Exeopen
#define Exmnt Exexmnt
-#define Emip Exemip
-#define Enopsmt Exenopsmt
+extern char Enomem[];
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*);
@@ -119,11 +113,15 @@
void Xwstat(Fsrpc*);
void slave(Fsrpc*);
+void io(int, int);
void reply(Fcall*, Fcall*, char*);
+void mounterror(char*);
+
Fid *getfid(int);
int freefid(int);
Fid *newfid(int);
Fsrpc *getsbuf(void);
+void putsbuf(Fsrpc*);
void initroot(void);
void fatal(char*, ...);
char* makepath(File*, char*);
@@ -141,8 +139,4 @@
void freeqid(Qidtab*);
char* estrdup(char*);
void* emallocz(uint);
-int readmessage(int, char*, int);
-
-#define notify(x)
-#define noted(x)
-
+int readmessage(int, char*, int);
--- a/exportfs/exportsrv.c
+++ b/exportfs/exportsrv.c
@@ -1,5 +1,6 @@
#include <u.h>
#include <libc.h>
+#include <auth.h>
#include <fcall.h>
#define Extern extern
#include "exportfs.h"
@@ -12,36 +13,29 @@
char Emip[] = "Mount in progress";
char Enopsmt[] = "Out of pseudo mount points";
char Enomem[] = "No memory";
-char Eversion[] = "Bad 9P2000 version";
+char Ereadonly[] = "File system read only";
-void*
-emallocz(uint n)
-{
- void *v;
+int readonly;
- v = mallocz(n, 1);
- if(v == nil)
- panic("out of memory");
- return v;
-}
-
-
void
Xversion(Fsrpc *t)
{
Fcall rhdr;
+ if(t->work.msize < 256){
+ reply(&t->work, &rhdr, "version: message size too small");
+ putsbuf(t);
+ return;
+ }
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;
+ rhdr.version = "9P2000";
+ if(strncmp(t->work.version, "9P", 2) != 0)
+ rhdr.version = "unknown";
reply(&t->work, &rhdr, 0);
- t->busy = 0;
+ putsbuf(t);
}
void
@@ -50,34 +44,37 @@
Fcall rhdr;
reply(&t->work, &rhdr, "exportfs: authentication not required");
- t->busy = 0;
+ putsbuf(t);
}
void
Xflush(Fsrpc *t)
{
- Fsrpc *w, *e;
Fcall rhdr;
+ Fsrpc *w;
+ Proc *m;
- e = &Workq[Nr_workbufs];
+ for(m = Proclist; m != nil; m = m->next){
+ w = m->busy;
+ if(w == nil || w->work.tag != t->work.oldtag)
+ continue;
- for(w = Workq; w < e; w++) {
- if(w->work.tag == t->work.oldtag) {
- DEBUG(DFD, "\tQ busy %d kp %d can %d\n", w->busy, w->kp, w->canint);
- if(w->busy && w->kp) {
- w->flushtag = t->work.tag;
- DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
- if(w->canint)
- kprocint(w->kp);
- t->busy = 0;
- return;
- }
+ lock(&m->lock);
+ w = m->busy;
+ if(w != nil && w->work.tag == t->work.oldtag) {
+ w->flushtag = t->work.tag;
+ DEBUG("\tset flushtag %d\n", t->work.tag);
+ kprocint(m->kp);
+ unlock(&m->lock);
+ putsbuf(t);
+ return;
}
+ unlock(&m->lock);
}
reply(&t->work, &rhdr, 0);
- DEBUG(DFD, "\tflush reply\n");
- t->busy = 0;
+ DEBUG("\tflush reply\n");
+ putsbuf(t);
}
void
@@ -87,51 +84,18 @@
Fid *f;
f = newfid(t->work.fid);
- if(f == 0) {
+ if(f == nil) {
reply(&t->work, &rhdr, Ebadfid);
- t->busy = 0;
+ putsbuf(t);
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++;
- }
+ f->f = root;
+ f->f->ref++;
rhdr.qid = f->f->qid;
reply(&t->work, &rhdr, 0);
- t->busy = 0;
+ putsbuf(t);
}
Fid*
@@ -140,15 +104,15 @@
Fid *n;
n = newfid(new);
- if(n == 0) {
+ if(n == nil) {
n = getfid(new);
- if(n == 0)
+ if(n == nil)
fatal("inconsistent fids");
if(n->fid >= 0)
close(n->fid);
freefid(new);
n = newfid(new);
- if(n == 0)
+ if(n == nil)
fatal("inconsistent fids2");
}
n->f = f->f;
@@ -166,9 +130,9 @@
int i;
f = getfid(t->work.fid);
- if(f == 0) {
+ if(f == nil) {
reply(&t->work, &rhdr, Ebadfid);
- t->busy = 0;
+ putsbuf(t);
return;
}
@@ -197,7 +161,7 @@
}
wf = file(f->f, t->work.wname[i]);
- if(wf == 0){
+ if(wf == nil){
errstr(err, sizeof err);
e = err;
break;
@@ -214,7 +178,7 @@
if(rhdr.nwqid > 0)
e = nil;
reply(&t->work, &rhdr, e);
- t->busy = 0;
+ putsbuf(t);
}
void
@@ -224,9 +188,9 @@
Fid *f;
f = getfid(t->work.fid);
- if(f == 0) {
+ if(f == nil) {
reply(&t->work, &rhdr, Ebadfid);
- t->busy = 0;
+ putsbuf(t);
return;
}
@@ -235,7 +199,7 @@
freefid(t->work.fid);
reply(&t->work, &rhdr, 0);
- t->busy = 0;
+ putsbuf(t);
}
void
@@ -249,9 +213,9 @@
uchar *statbuf;
f = getfid(t->work.fid);
- if(f == 0) {
+ if(f == nil) {
reply(&t->work, &rhdr, Ebadfid);
- t->busy = 0;
+ putsbuf(t);
return;
}
if(f->fid >= 0)
@@ -265,7 +229,7 @@
if(d == nil) {
errstr(err, sizeof err);
reply(&t->work, &rhdr, err);
- t->busy = 0;
+ putsbuf(t);
return;
}
@@ -278,7 +242,7 @@
rhdr.stat = statbuf;
reply(&t->work, &rhdr, 0);
free(statbuf);
- t->busy = 0;
+ putsbuf(t);
}
static int
@@ -300,10 +264,15 @@
Fid *f;
File *nf;
+ if(readonly) {
+ reply(&t->work, &rhdr, Ereadonly);
+ putsbuf(t);
+ return;
+ }
f = getfid(t->work.fid);
- if(f == 0) {
+ if(f == nil) {
reply(&t->work, &rhdr, Ebadfid);
- t->busy = 0;
+ putsbuf(t);
return;
}
@@ -314,15 +283,15 @@
if(f->fid < 0) {
errstr(err, sizeof err);
reply(&t->work, &rhdr, err);
- t->busy = 0;
+ putsbuf(t);
return;
}
nf = file(f->f, t->work.name);
- if(nf == 0) {
+ if(nf == nil) {
errstr(err, sizeof err);
reply(&t->work, &rhdr, err);
- t->busy = 0;
+ putsbuf(t);
return;
}
@@ -332,7 +301,7 @@
rhdr.qid = f->f->qid;
rhdr.iounit = getiounit(f->fid);
reply(&t->work, &rhdr, 0);
- t->busy = 0;
+ putsbuf(t);
}
void
@@ -342,20 +311,25 @@
Fcall rhdr;
Fid *f;
+ if(readonly) {
+ reply(&t->work, &rhdr, Ereadonly);
+ putsbuf(t);
+ return;
+ }
f = getfid(t->work.fid);
- if(f == 0) {
+ if(f == nil) {
reply(&t->work, &rhdr, Ebadfid);
- t->busy = 0;
+ putsbuf(t);
return;
}
path = makepath(f->f, "");
- DEBUG(DFD, "\tremove: %s\n", path);
+ DEBUG("\tremove: %s\n", path);
if(remove(path) < 0) {
free(path);
errstr(err, sizeof err);
reply(&t->work, &rhdr, err);
- t->busy = 0;
+ putsbuf(t);
return;
}
free(path);
@@ -366,7 +340,7 @@
freefid(t->work.fid);
reply(&t->work, &rhdr, 0);
- t->busy = 0;
+ putsbuf(t);
}
void
@@ -379,10 +353,15 @@
char *strings;
Dir d;
+ if(readonly) {
+ reply(&t->work, &rhdr, Ereadonly);
+ putsbuf(t);
+ return;
+ }
f = getfid(t->work.fid);
- if(f == 0) {
+ if(f == nil) {
reply(&t->work, &rhdr, Ebadfid);
- t->busy = 0;
+ putsbuf(t);
return;
}
strings = emallocz(t->work.nstat); /* ample */
@@ -389,7 +368,7 @@
if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
rerrstr(err, sizeof err);
reply(&t->work, &rhdr, err);
- t->busy = 0;
+ putsbuf(t);
free(strings);
return;
}
@@ -414,73 +393,83 @@
reply(&t->work, &rhdr, 0);
}
free(strings);
- t->busy = 0;
+ putsbuf(t);
}
void
slave(Fsrpc *f)
{
- Proc *p;
- void *kp;
static int nproc;
+ Proc *m, **l;
+ Fcall rhdr;
- for(;;) {
- for(p = Proclist; p; p = p->next) {
- if(p->busy == 0) {
- f->kp = p->kp;
- p->busy = 1;
- kp = rendezvous(p->kp, f);
- if(kp != p->kp)
- fatal("rendezvous sync fail");
+ if(readonly){
+ switch(f->work.type){
+ case Twrite:
+ reply(&f->work, &rhdr, Ereadonly);
+ putsbuf(f);
+ return;
+ case Topen:
+ if((f->work.mode&3) == OWRITE || (f->work.mode&(OTRUNC|ORCLOSE))){
+ reply(&f->work, &rhdr, Ereadonly);
+ putsbuf(f);
return;
}
}
+ }
+ for(;;) {
+ for(l = &Proclist; (m = *l) != nil; l = &m->next) {
+ if(m->busy != nil)
+ continue;
- if(++nproc > MAXPROC)
- fatal("too many procs");
+ m->busy = f;
+ while(rendezvous(m, f) == (void*)~0)
+ ;
- kp = kproc("slave", blockingslave, nil);
- DEBUG(DFD, "slave kp %p\n", kp);
+ /* swept a slave proc */
+ if(f == nil){
+ *l = m->next;
+ free(m);
+ nproc--;
+ break;
+ }
+ f = nil;
- p = malloc(sizeof(Proc));
- if(p == 0)
- fatal("out of memory");
+ /*
+ * as long as the number of slave procs
+ * is small, dont bother sweeping.
+ */
+ if(nproc < 16)
+ break;
+ }
+ if(f == nil)
+ return;
- p->busy = 0;
- p->kp = kp;
- p->next = Proclist;
- Proclist = p;
-
-DEBUG(DFD, "parent %p rendez\n", kp);
- rendezvous(kp, p);
-DEBUG(DFD, "parent %p went\n", kp);
+ m = emallocz(sizeof(Proc));
+ m->kp = kproc("slave", blockingslave, m);
+ m->next = Proclist;
+ Proclist = m;
+ nproc++;
}
}
void
-blockingslave(void *x)
+blockingslave(void *arg)
{
+ Proc *m;
Fsrpc *p;
Fcall rhdr;
- Proc *m;
- void *kp;
- USED(x);
+ m = (Proc*)arg;
- kp = getkproc();
-
- notify(flushaction);
-
-DEBUG(DFD, "blockingslave %p rendez\n", kp);
- m = rendezvous(kp, 0);
-DEBUG(DFD, "blockingslave %p rendez got %p\n", kp, m);
-
for(;;) {
- p = rendezvous(kp, kp);
- if((uintptr)p == ~(uintptr)0) /* Interrupted */
+ p = rendezvous(m, nil);
+ if(p == (void*)~0) /* Interrupted */
continue;
+ if(p == nil) /* Swept */
+ break;
- DEBUG(DFD, "\tslave: %p %F b %d p %p\n", kp, &p->work, p->busy, p->kp);
+ DEBUG("\tslave: %p %F\n", m->kp, &p->work);
if(p->flushtag != NOTAG)
goto flushme;
@@ -500,14 +489,18 @@
default:
reply(&p->work, &rhdr, "exportfs: slave type error");
}
- if(p->flushtag != NOTAG) {
flushme:
+ lock(&m->lock);
+ m->busy = nil;
+ unlock(&m->lock);
+
+ /* no more flushes can come in now */
+ if(p->flushtag != NOTAG) {
p->work.type = Tflush;
p->work.tag = p->flushtag;
reply(&p->work, &rhdr, 0);
}
- p->busy = 0;
- m->busy = 0;
+ putsbuf(p);
}
}
@@ -529,7 +522,7 @@
work = &p->work;
f = getfid(work->fid);
- if(f == 0) {
+ if(f == nil) {
reply(work, &rhdr, Ebadfid);
return;
}
@@ -539,17 +532,9 @@
}
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 */
+ DEBUG("\topen: %s %d\n", path, work->mode);
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);
@@ -564,8 +549,9 @@
goto Error;
}
- DEBUG(DFD, "\topen: fd %d\n", f->fid);
+ DEBUG("\topen: fd %d\n", f->fid);
f->mode = work->mode;
+ f->offset = 0;
rhdr.iounit = getiounit(f->fid);
rhdr.qid = f->f->qid;
reply(work, &rhdr, 0);
@@ -582,22 +568,20 @@
work = &p->work;
f = getfid(work->fid);
- if(f == 0) {
+ if(f == nil) {
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);
+ if(data == nil) {
+ reply(work, &rhdr, Enomem);
+ return;
+ }
/* 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);
@@ -604,9 +588,8 @@
reply(work, &rhdr, err);
return;
}
+ DEBUG("\tread: fd=%d %d bytes\n", f->fid, r);
- DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
-
rhdr.data = data;
rhdr.count = r;
reply(work, &rhdr, 0);
@@ -624,17 +607,13 @@
work = &p->work;
f = getfid(work->fid);
- if(f == 0) {
+ if(f == nil) {
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);
@@ -641,7 +620,7 @@
return;
}
- DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
+ DEBUG("\twrite: %d bytes fd=%d\n", n, f->fid);
rhdr.count = n;
reply(work, &rhdr, 0);
@@ -652,18 +631,4 @@
{
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);
}
--- /dev/null
+++ b/exportfs/io.c
@@ -1,0 +1,490 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#define Extern
+#include "exportfs.h"
+
+#define QIDPATH ((1LL<<48)-1)
+vlong newqid = 0;
+
+void (*fcalls[])(Fsrpc*) =
+{
+ [Tversion] Xversion,
+ [Tauth] Xauth,
+ [Tflush] Xflush,
+ [Tattach] Xattach,
+ [Twalk] Xwalk,
+ [Topen] slave,
+ [Tcreate] Xcreate,
+ [Tclunk] Xclunk,
+ [Tread] slave,
+ [Twrite] slave,
+ [Tremove] Xremove,
+ [Tstat] Xstat,
+ [Twstat] Xwstat,
+};
+
+/* accounting and debugging counters */
+int filecnt;
+int freecnt;
+int qidcnt;
+int qfreecnt;
+int ncollision;
+
+static int netfd[2];
+
+/*
+ * Start serving file requests from the network
+ */
+void
+io(int rfd, int wfd)
+{
+ Fsrpc *r;
+ int n;
+
+ netfd[0] = rfd;
+ netfd[1] = wfd;
+
+ for(;;) {
+ r = getsbuf();
+ n = read9pmsg(netfd[0], r->buf, messagesize);
+ if(n <= 0)
+ fatal(nil);
+ if(convM2S(r->buf, n, &r->work) != n)
+ fatal("convM2S format error");
+
+ DEBUG("%F\n", &r->work);
+ (fcalls[r->work.type])(r);
+ }
+}
+
+void
+reply(Fcall *r, Fcall *t, char *err)
+{
+ uchar *data;
+ int n;
+
+ t->tag = r->tag;
+ t->fid = r->fid;
+ if(err != nil) {
+ t->type = Rerror;
+ t->ename = err;
+ }
+ else
+ t->type = r->type + 1;
+
+ DEBUG("\t%F\n", t);
+
+ data = malloc(messagesize); /* not mallocz; no need to clear */
+ if(data == nil)
+ fatal(Enomem);
+ n = convS2M(t, data, messagesize);
+ if(write(netfd[1], data, n) != n){
+ /* not fatal, might have got a note due to flush */
+ fprint(2, "exportfs: short write in reply: %r\n");
+ }
+ free(data);
+}
+
+void
+mounterror(char *err)
+{
+ Fsrpc *r;
+ int n;
+
+ r = getsbuf();
+ r->work.tag = NOTAG;
+ r->work.fid = NOFID;
+ r->work.type = Rerror;
+ r->work.ename = err;
+ n = convS2M(&r->work, r->buf, messagesize);
+ write(netfd[1], r->buf, n);
+ exits(err);
+}
+
+Fid *
+getfid(int nr)
+{
+ Fid *f;
+
+ for(f = fidhash(nr); f != nil; f = f->next)
+ if(f->nr == nr)
+ return f;
+
+ return nil;
+}
+
+int
+freefid(int nr)
+{
+ Fid *f, **l;
+ char buf[128];
+
+ l = &fidhash(nr);
+ for(f = *l; f != nil; f = f->next) {
+ if(f->nr == nr) {
+ if(f->mid != -1) {
+ snprint(buf, sizeof(buf), "/mnt/exportfs/%d", f->mid);
+ unmount(0, buf);
+ }
+ if(f->f != nil) {
+ freefile(f->f);
+ f->f = nil;
+ }
+ if(f->dir != nil){
+ free(f->dir);
+ f->dir = 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 != nil; new = new->next)
+ if(new->nr == nr)
+ return nil;
+
+ if(fidfree == nil) {
+ fidfree = emallocz(sizeof(Fid) * Fidchunk);
+
+ for(i = 0; i < Fidchunk-1; i++)
+ fidfree[i].next = &fidfree[i+1];
+
+ fidfree[Fidchunk-1].next = nil;
+ }
+
+ new = fidfree;
+ fidfree = new->next;
+
+ memset(new, 0, sizeof(Fid));
+ new->next = *l;
+ *l = new;
+ new->nr = nr;
+ new->fid = -1;
+ new->mid = -1;
+
+ return new;
+}
+
+static struct {
+ Lock lock;
+ Fsrpc *free;
+
+ /* statistics */
+ int nalloc;
+ int nfree;
+} sbufalloc;
+
+Fsrpc *
+getsbuf(void)
+{
+ Fsrpc *w;
+
+ lock(&sbufalloc.lock);
+ w = sbufalloc.free;
+ if(w != nil){
+ sbufalloc.free = w->next;
+ w->next = nil;
+ sbufalloc.nfree--;
+ unlock(&sbufalloc.lock);
+ } else {
+ sbufalloc.nalloc++;
+ unlock(&sbufalloc.lock);
+ w = emallocz(sizeof(*w) + messagesize);
+ }
+ w->flushtag = NOTAG;
+ return w;
+}
+
+void
+putsbuf(Fsrpc *w)
+{
+ w->flushtag = NOTAG;
+ lock(&sbufalloc.lock);
+ w->next = sbufalloc.free;
+ sbufalloc.free = w;
+ sbufalloc.nfree++;
+ unlock(&sbufalloc.lock);
+}
+
+void
+freefile(File *f)
+{
+ File *parent, *child;
+
+ while(--f->ref == 0){
+ freecnt++;
+ DEBUG("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);
+ free(f);
+ f = parent;
+ }
+}
+
+File *
+file(File *parent, char *name)
+{
+ Dir *dir;
+ char *path;
+ File *f;
+
+ DEBUG("\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 != nil; 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 == nil)
+ 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 = emallocz(n);
+ 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;
+
+ if(--q->ref)
+ 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("collision on %s\n", d->name);
+ /* collision: find a new one */
+ ncollision++;
+ path &= QIDPATH;
+ ++newqid;
+ if(newqid >= (1<<16)){
+ DEBUG("collision wraparound\n");
+ newqid = 1;
+ }
+ path |= newqid<<48;
+ DEBUG("assign qid %.16llux\n", path);
+ }
+ qidcnt++;
+ q = emallocz(sizeof(Qidtab));
+ 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;
+ Proc *m;
+
+ if(s != nil) {
+ va_start(arg, s);
+ vsnprint(buf, ERRMAX, s, arg);
+ va_end(arg);
+ }
+
+ /* Clear away the slave children */
+ for(m = Proclist; m != nil; m = m->next)
+ kprocint(m->kp);
+
+ if(s != nil) {
+ DEBUG("%s\n", buf);
+ sysfatal("%s", buf); /* caution: buf could contain '%' */
+ } else
+ exits(nil);
+}
+
+void*
+emallocz(uint n)
+{
+ void *p;
+
+ p = mallocz(n, 1);
+ if(p == nil)
+ fatal(Enomem);
+ setmalloctag(p, getcallerpc(&n));
+ return p;
+}
--
⑨