diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-03-14 21:15:16 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-03-14 21:15:16 +0100 |
commit | 1c2fc5208163b09667482c357934cd51b5938f4f (patch) | |
tree | e9606395e3d1565d3adff4b545e0a3504ef615ab /sys/src | |
parent | 08e433f31db74945aecfcad2755ccf274e849810 (diff) |
ramfs: replace with new lib9p based implementation
old ramfs had a limit on the number of files it could serve
and file size was limited to maximum allocaiton size.
the new implementation uses multiple memory chunks to back file data
in a private compactable memory pool to overcome these limits.
files can be sparse. file metadata is maintained by 9pfile data
structures of lib9p.
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/cmd/ramfs.c | 1210 |
1 files changed, 404 insertions, 806 deletions
diff --git a/sys/src/cmd/ramfs.c b/sys/src/cmd/ramfs.c index 57ca02daa..57ef79b88 100644 --- a/sys/src/cmd/ramfs.c +++ b/sys/src/cmd/ramfs.c @@ -2,713 +2,321 @@ #include <libc.h> #include <auth.h> #include <fcall.h> - +#include <thread.h> +#include <9p.h> #include <pool.h> -/* - * Rather than reading /adm/users, which is a lot of work for - * a toy program, we assume all groups have the form - * NNN:user:user: - * meaning that each user is the leader of his own group. - */ - -enum -{ - OPERM = 0x3, /* mask of all permission types in open mode */ - Nram = 2048, - Maxsize = 768*1024*1024, - Maxfdata = 8192, - Maxulong= (1ULL << 32) - 1, -}; +char Ebadoff[] = "bad file offset or count"; +char Eexist[] = "file already exists"; +char Enomem[] = "no memory"; +char Eperm[] = "permission denied"; +char Enotowner[] = "not owner"; +char Elocked[] = "file locked"; -typedef struct Fid Fid; -typedef struct Ram Ram; +enum { + Tdat = 0xbabababa, + Tind = 0xdadadada, -struct Fid -{ - short busy; - short open; - short rclose; - int fid; - Fid *next; - char *user; - Ram *ram; + ESIZE = 64*1024, }; -struct Ram -{ - short busy; - short open; - long parent; /* index in Ram array */ - Qid qid; - long perm; - char *name; - ulong atime; - ulong mtime; - char *user; - char *group; - char *muid; - char *data; - long ndata; -}; +#define MAXFSIZE ((0x7fffffffll/sizeof(Ram*))*ESIZE) -enum +typedef struct Ram Ram; +struct Ram { - Pexec = 1, - Pwrite = 2, - Pread = 4, - Pother = 1, - Pgroup = 8, - Powner = 64, -}; - -ulong path; /* incremented for each new file */ -Fid *fids; -Ram ram[Nram]; -int nram; -int mfd[2]; -char *user; -uchar mdata[IOHDRSZ+Maxfdata]; -uchar rdata[Maxfdata]; /* buffer for data in reply */ -uchar statbuf[STATMAX]; -Fcall thdr; -Fcall rhdr; -int messagesize = sizeof mdata; - -Fid * newfid(int); -uint ramstat(Ram*, uchar*, uint); -void error(char*); -void io(void); -void *erealloc(void*, ulong); -void *emalloc(ulong); -char *estrdup(char*); -void usage(void); -int perm(Fid*, Ram*, int); - -char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*), - *rattach(Fid*), *rwalk(Fid*), - *ropen(Fid*), *rcreate(Fid*), - *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), - *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*); - -int needfid[] = { - [Tversion] 0, - [Tflush] 0, - [Tauth] 0, - [Tattach] 0, - [Twalk] 1, - [Topen] 1, - [Tcreate] 1, - [Tread] 1, - [Twrite] 1, - [Tclunk] 1, - [Tremove] 1, - [Tstat] 1, - [Twstat] 1, -}; - -char *(*fcalls[])(Fid*) = { - [Tversion] rversion, - [Tflush] rflush, - [Tauth] rauth, - [Tattach] rattach, - [Twalk] rwalk, - [Topen] ropen, - [Tcreate] rcreate, - [Tread] rread, - [Twrite] rwrite, - [Tclunk] rclunk, - [Tremove] rremove, - [Tstat] rstat, - [Twstat] rwstat, + int type; + int size; + Ram **link; + Ram *ent[]; }; -char Eperm[] = "permission denied"; -char Enotdir[] = "not a directory"; -char Enoauth[] = "ramfs: authentication not required"; -char Enotexist[] = "file does not exist"; -char Einuse[] = "file in use"; -char Eexist[] = "file exists"; -char Eisdir[] = "file is a directory"; -char Enotowner[] = "not owner"; -char Eisopen[] = "file already open for I/O"; -char Excl[] = "exclusive use file already open"; -char Ename[] = "illegal name"; -char Eversion[] = "unknown 9P version"; -char Enotempty[] = "directory not empty"; - -int debug; int private; -static int memlim = 1; - -void -notifyf(void *a, char *s) +void* +ramalloc(ulong size) { - USED(a); - if(strncmp(s, "interrupt", 9) == 0) - noted(NCONT); - noted(NDFLT); + void *v; + + v = sbrk(size); + if(v == (void*)-1) + return nil; + return v; } void -main(int argc, char *argv[]) +rammoved(void*, void *to) { - Ram *r; - char *defmnt, *service; - int p[2]; - int fd; - int stdio = 0; - int mountflags; - - service = "ramfs"; - defmnt = "/tmp"; - mountflags = 0; - ARGBEGIN{ - case 'i': - defmnt = 0; - stdio = 1; - mfd[0] = 0; - mfd[1] = 1; - break; - case 'm': - defmnt = EARGF(usage()); - break; - case 'p': - private++; - break; - case 's': - defmnt = 0; - break; - case 'u': - memlim = 0; /* unlimited memory consumption */ - mainmem->maxsize = (uintptr)~0; - break; - case 'D': - debug = 1; - break; - case 'S': - defmnt = 0; - service = EARGF(usage()); - break; - case 'b': - mountflags |= MBEFORE; - break; - case 'c': - mountflags |= MCREATE; - break; - case 'a': - mountflags |= MAFTER; - break; - default: - usage(); - }ARGEND - if(mountflags == 0) - mountflags = MREPL | MCREATE; + Ram **link, **elink, *x = to; - if(pipe(p) < 0) - error("pipe failed"); - if(!stdio){ - mfd[0] = p[0]; - mfd[1] = p[0]; - if(defmnt == 0){ - char buf[64]; - snprint(buf, sizeof buf, "#s/%s", service); - fd = create(buf, OWRITE|ORCLOSE, 0666); - if(fd < 0) - error("create failed"); - sprint(buf, "%d", p[1]); - if(write(fd, buf, strlen(buf)) < 0) - error("writing service file"); - } - } + *x->link = x; + if(x->type != Tind) + return; - user = getuser(); - notify(notifyf); - nram = 1; - r = &ram[0]; - r->busy = 1; - r->data = 0; - r->ndata = 0; - r->perm = DMDIR | 0775; - r->qid.type = QTDIR; - r->qid.path = 0LL; - r->qid.vers = 0; - r->parent = 0; - r->user = user; - r->group = user; - r->muid = user; - r->atime = time(0); - r->mtime = r->atime; - r->name = estrdup("."); - - if(debug) { - fmtinstall('F', fcallfmt); - fmtinstall('M', dirmodefmt); - } - switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ - case -1: - error("fork"); - case 0: - close(p[1]); - io(); - break; - default: - close(p[0]); /* don't deadlock if child fails */ - if(defmnt && mount(p[1], -1, defmnt, mountflags, "") < 0) - error("mount failed"); - } - exits(0); + link = x->ent; + for(elink = link + (x->size / sizeof(Ram*)); link < elink; link++) + if((x = *link) != nil) + x->link = link; } -char* -rversion(Fid*) +void +ramnolock(Pool*) { - Fid *f; - - for(f = fids; f; f = f->next) - if(f->busy) - rclunk(f); - if(thdr.msize > sizeof mdata) - rhdr.msize = sizeof mdata; - else - rhdr.msize = thdr.msize; - messagesize = rhdr.msize; - if(strncmp(thdr.version, "9P2000", 6) != 0) - return Eversion; - rhdr.version = "9P2000"; - return 0; } -char* -rauth(Fid*) -{ - return "ramfs: no authentication required"; -} +Pool rampool = { + .name= "ram", + .maxsize= 800*1024*1024, + .minarena= 4*1024, + .quantum= 32, + .alloc= ramalloc, + .move= rammoved, + .lock= ramnolock, + .unlock= ramnolock, + .flags= 0, +}; -char* -rflush(Fid *f) +void +accessfile(File *f, int a) { - USED(f); - return 0; + f->atime = time(0); + if(a & AWRITE){ + f->mtime = f->atime; + f->qid.vers++; + } } -char* -rattach(Fid *f) +void +fsread(Req *r) { - /* no authentication! */ - f->busy = 1; - f->rclose = 0; - f->ram = &ram[0]; - rhdr.qid = f->ram->qid; - if(thdr.uname[0]) - f->user = estrdup(thdr.uname); - else - f->user = "none"; - if(strcmp(user, "none") == 0) - user = f->user; - return 0; -} + int o, n, i, count; + vlong top, off; + File *f; + Ram *x; + char *p; -char* -clone(Fid *f, Fid **nf) -{ - if(f->open) - return Eisopen; - if(f->ram->busy == 0) - return Enotexist; - *nf = newfid(thdr.newfid); - (*nf)->busy = 1; - (*nf)->open = 0; - (*nf)->rclose = 0; - (*nf)->ram = f->ram; - (*nf)->user = f->user; /* no ref count; the leakage is minor */ - return 0; -} + f = r->fid->file; + off = r->ifcall.offset; + count = r->ifcall.count; -char* -rwalk(Fid *f) -{ - Ram *r, *fram; - char *name; - Ram *parent; - Fid *nf; - char *err; - ulong t; - int i; - - err = nil; - nf = nil; - rhdr.nwqid = 0; - if(thdr.newfid != thdr.fid){ - err = clone(f, &nf); - if(err) - return err; - f = nf; /* walk the new fid */ - } - fram = f->ram; - if(thdr.nwname > 0){ - t = time(0); - for(i=0; i<thdr.nwname && i<MAXWELEM; i++){ - if((fram->qid.type & QTDIR) == 0){ - err = Enotdir; - break; - } - if(fram->busy == 0){ - err = Enotexist; - break; - } - fram->atime = t; - name = thdr.wname[i]; - if(strcmp(name, ".") == 0){ - Found: - rhdr.nwqid++; - rhdr.wqid[i] = fram->qid; - continue; - } - parent = &ram[fram->parent]; - if(!perm(f, parent, Pexec)){ - err = Eperm; - break; - } - if(strcmp(name, "..") == 0){ - fram = parent; - goto Found; - } - for(r=ram; r < &ram[nram]; r++) - if(r->busy && r->parent==fram-ram && strcmp(name, r->name)==0){ - fram = r; - goto Found; - } - break; - } - if(i==0 && err == nil) - err = Enotexist; - } - if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){ - /* clunk the new fid, which is the one we walked */ - f->busy = 0; - f->ram = nil; + if(count == 0 || off >= f->length || f->aux == nil){ + r->ofcall.count = 0; + respond(r, nil); + return; } - if(rhdr.nwqid > 0) - err = nil; /* didn't get everything in 9P2000 right! */ - if(rhdr.nwqid == thdr.nwname) /* update the fid after a successful walk */ - f->ram = fram; - return err; -} -char * -ropen(Fid *f) -{ - Ram *r; - int mode, trunc; - - if(f->open) - return Eisopen; - r = f->ram; - if(r->busy == 0) - return Enotexist; - if(r->perm & DMEXCL) - if(r->open) - return Excl; - mode = thdr.mode; - if(r->qid.type & QTDIR){ - if(mode != OREAD) - return Eperm; - rhdr.qid = r->qid; - return 0; + top = off + count; + if(top > MAXFSIZE){ + respond(r, Ebadoff); + return; } - if(mode & ORCLOSE){ - /* can't remove root; must be able to write parent */ - if(r->qid.path==0 || !perm(f, &ram[r->parent], Pwrite)) - return Eperm; - f->rclose = 1; + + if(top > f->length){ + top = f->length; + count = top - off; } - trunc = mode & OTRUNC; - mode &= OPERM; - if(mode==OWRITE || mode==ORDWR || trunc) - if(!perm(f, r, Pwrite)) - return Eperm; - if(mode==OREAD || mode==ORDWR) - if(!perm(f, r, Pread)) - return Eperm; - if(mode==OEXEC) - if(!perm(f, r, Pexec)) - return Eperm; - if(trunc && (r->perm&DMAPPEND)==0){ - r->ndata = 0; - if(r->data) - free(r->data); - r->data = 0; - r->qid.vers++; + p = (char*)r->ofcall.data; + while(count > 0){ + i = off / ESIZE; + o = off % ESIZE; + + x = (Ram*)f->aux; + if(i < (x->size / sizeof(Ram*))) + x = x->ent[i]; + else + x = nil; + if(x != nil && o < x->size){ + n = x->size - o; + if(n > count) + n = count; + memmove(p, (char*)&x[1] + o, n); + } else { + n = ESIZE - o; + if(n > count) + n = count; + memset(p, 0, n); + } + p += n; + off += n; + count -= n; } - rhdr.qid = r->qid; - rhdr.iounit = messagesize-IOHDRSZ; - f->open = 1; - r->open++; - return 0; -} + accessfile(f, AREAD); -char * -rcreate(Fid *f) -{ - Ram *r; - char *name; - long parent, prm; - - if(f->open) - return Eisopen; - if(f->ram->busy == 0) - return Enotexist; - parent = f->ram - ram; - if((f->ram->qid.type&QTDIR) == 0) - return Enotdir; - /* must be able to write parent */ - if(!perm(f, f->ram, Pwrite)) - return Eperm; - prm = thdr.perm; - name = thdr.name; - if(strcmp(name, ".")==0 || strcmp(name, "..")==0) - return Ename; - for(r=ram; r<&ram[nram]; r++) - if(r->busy && parent==r->parent) - if(strcmp((char*)name, r->name)==0) - return Einuse; - for(r=ram; r->busy; r++) - if(r == &ram[Nram-1]) - return "no free ram resources"; - r->busy = 1; - r->qid.path = ++path; - r->qid.vers = 0; - if(prm & DMDIR) - r->qid.type |= QTDIR; - r->parent = parent; - free(r->name); - r->name = estrdup(name); - r->user = f->user; - r->group = f->ram->group; - r->muid = f->ram->muid; - if(prm & DMDIR) - prm = (prm&~0777) | (f->ram->perm&prm&0777); - else - prm = (prm&(~0777|0111)) | (f->ram->perm&prm&0666); - r->perm = prm; - r->ndata = 0; - if(r-ram >= nram) - nram = r - ram + 1; - r->atime = time(0); - r->mtime = r->atime; - f->ram->mtime = r->atime; - f->ram = r; - rhdr.qid = r->qid; - rhdr.iounit = messagesize-IOHDRSZ; - f->open = 1; - if(thdr.mode & ORCLOSE) - f->rclose = 1; - r->open++; - return 0; + r->ofcall.count = p - (char*)r->ofcall.data; + respond(r, nil); } -char* -rread(Fid *f) +void +fswrite(Req *r) { - Ram *r; - uchar *buf; - vlong off; - int n, m, cnt; - - if(f->ram->busy == 0) - return Enotexist; - n = 0; - rhdr.count = 0; - rhdr.data = (char*)rdata; - if (thdr.offset < 0) - return "negative seek offset"; - off = thdr.offset; - buf = rdata; - cnt = thdr.count; - if(cnt > messagesize) /* shouldn't happen, anyway */ - cnt = messagesize; - if(cnt < 0) - return "negative read count"; - if(f->ram->qid.type & QTDIR){ - for(r=ram+1; off > 0; r++){ - if(r->busy && r->parent==f->ram-ram) - off -= ramstat(r, statbuf, sizeof statbuf); - if(r == &ram[nram-1]) - return 0; - } - for(; r<&ram[nram] && n < cnt; r++){ - if(!r->busy || r->parent!=f->ram-ram) - continue; - m = ramstat(r, buf+n, cnt-n); - if(m == 0) - break; - n += m; - } - rhdr.data = (char*)rdata; - rhdr.count = n; - return 0; + int o, n, i, count; + Ram *x, **link; + vlong top, off; + File *f; + char *p; + + f = r->fid->file; + off = r->ifcall.offset; + count = r->ifcall.count; + + if(f->mode & DMAPPEND) + off = f->length; + + if(count == 0){ + r->ofcall.count = 0; + respond(r, nil); + return; } - r = f->ram; - if(off >= r->ndata) - return 0; - r->atime = time(0); - n = cnt; - if(off+n > r->ndata) - n = r->ndata - off; - rhdr.data = r->data+off; - rhdr.count = n; - return 0; -} -char* -rwrite(Fid *f) -{ - Ram *r; - vlong off; - int cnt; - - r = f->ram; - rhdr.count = 0; - if(r->busy == 0) - return Enotexist; - if (thdr.offset < 0) - return "negative seek offset"; - off = thdr.offset; - if(r->perm & DMAPPEND) - off = r->ndata; - cnt = thdr.count; - if(cnt < 0) - return "negative write count"; - if(r->qid.type & QTDIR) - return Eisdir; - if(memlim && off+cnt >= Maxsize) /* sanity check */ - return "write too big"; - if(off+cnt > r->ndata) - r->data = erealloc(r->data, off+cnt); - if(off > r->ndata) - memset(r->data+r->ndata, 0, off-r->ndata); - if(off+cnt > r->ndata) - r->ndata = off+cnt; - memmove(r->data+off, thdr.data, cnt); - r->qid.vers++; - r->mtime = time(0); - rhdr.count = cnt; - return 0; -} + top = off + count; + if(top > MAXFSIZE){ + respond(r, Ebadoff); + return; + } -static int -emptydir(Ram *dr) -{ - long didx = dr - ram; - Ram *r; + n = ((top + ESIZE-1)/ESIZE) * sizeof(Ram*); + x = (Ram*)f->aux; + if(x == nil || x->size < n){ + x = poolrealloc(&rampool, x, sizeof(Ram) + n); + if(x == nil){ + respond(r, Enomem); + return; + } + link = (Ram**)&f->aux; + if(*link == nil){ + memset(x, 0, sizeof(Ram)); + x->type = Tind; + x->link = link; + *link = x; + } else if(x != *link) + rammoved(*link, x); + memset((char*)&x[1] + x->size, 0, n - x->size); + x->size = n; + } - for(r=ram; r<&ram[nram]; r++) - if(r->busy && didx==r->parent) - return 0; - return 1; -} + p = (char*)r->ifcall.data; + while(count > 0){ + i = off / ESIZE; + o = off % ESIZE; + + n = ESIZE - o; + if(n > count) + n = count; + + x = ((Ram*)f->aux)->ent[i]; + if(x == nil || x->size < o+n){ + x = poolrealloc(&rampool, x, sizeof(Ram) + o+n); + if(x == nil){ + respond(r, Enomem); + return; + } + link = &((Ram*)f->aux)->ent[i]; + if(*link == nil){ + memset(x, 0, sizeof(Ram)); + x->type = Tdat; + } + if(o > x->size) + memset((char*)&x[1] + x->size, 0, o - x->size); + x->size = o + n; + x->link = link; + *link = x; + } -char * -realremove(Ram *r) -{ - if(r->qid.type & QTDIR && !emptydir(r)) - return Enotempty; - r->ndata = 0; - if(r->data) - free(r->data); - r->data = 0; - r->parent = 0; - memset(&r->qid, 0, sizeof r->qid); - free(r->name); - r->name = nil; - r->busy = 0; - return nil; -} + memmove((char*)&x[1] + o, p, n); + p += n; + off += n; + count -= n; + } -char * -rclunk(Fid *f) -{ - char *e = nil; - - if(f->open) - f->ram->open--; - if(f->rclose) - e = realremove(f->ram); - f->busy = 0; - f->open = 0; - f->ram = 0; - return e; -} + if(top > f->length) + f->length = top; + accessfile(f, AWRITE); -char * -rremove(Fid *f) -{ - Ram *r; - - if(f->open) - f->ram->open--; - f->busy = 0; - f->open = 0; - r = f->ram; - f->ram = 0; - if(r->qid.path == 0 || !perm(f, &ram[r->parent], Pwrite)) - return Eperm; - ram[r->parent].mtime = time(0); - return realremove(r); + r->ofcall.count = p - (char*)r->ifcall.data; + respond(r, nil); } -char * -rstat(Fid *f) +void +truncfile(File *f, vlong l) { - if(f->ram->busy == 0) - return Enotexist; - rhdr.nstat = ramstat(f->ram, statbuf, sizeof statbuf); - rhdr.stat = statbuf; - return 0; + int i, o, n; + Ram *x; + + x = (Ram*)f->aux; + if(x != nil){ + n = x->size / sizeof(Ram*); + i = l / ESIZE; + if(i < n){ + o = l % ESIZE; + if(o != 0 && x->ent[i] != nil){ + x->ent[i]->size = o * sizeof(Ram*); + i++; + } + while(i < n){ + if(x->ent[i] != nil){ + poolfree(&rampool, x->ent[i]); + x->ent[i] = nil; + } + i++; + } + } + if(l == 0){ + poolfree(&rampool, (Ram*)f->aux); + f->aux = nil; + } + } + f->length = l; } -char * -rwstat(Fid *f) +void +fswstat(Req *r) { - Ram *r, *s; - Dir dir; + File *f, *w; + char *u; - if(f->ram->busy == 0) - return Enotexist; - convM2D(thdr.stat, thdr.nstat, &dir, (char*)statbuf); - r = f->ram; + f = r->fid->file; + u = r->fid->uid; /* * To change length, must have write permission on file. */ - if(dir.length!=~0 && dir.length!=r->ndata){ - if(!perm(f, r, Pwrite)) - return Eperm; + if(r->d.length != ~0 && r->d.length != f->length){ + if(r->d.length > MAXFSIZE){ + respond(r, Ebadoff); + return; + } + if(!hasperm(f, u, AWRITE) || (r->d.mode & DMDIR) != 0) + goto Perm; } /* - * To change name, must have write permission in parent - * and name must be unique. + * To change name, must have write permission in parent. */ - if(dir.name[0]!='\0' && strcmp(dir.name, r->name)!=0){ - if(!perm(f, &ram[r->parent], Pwrite)) - return Eperm; - for(s=ram; s<&ram[nram]; s++) - if(s->busy && s->parent==r->parent) - if(strcmp(dir.name, s->name)==0) - return Eexist; + if(r->d.name[0] != '\0' && strcmp(r->d.name, f->name) != 0){ + if((w = f->parent) == nil) + goto Perm; + incref(w); + if(!hasperm(w, u, AWRITE)){ + closefile(w); + goto Perm; + } + if((w = walkfile(w, r->d.name)) != nil){ + closefile(w); + respond(r, Eexist); + return; + } } /* * To change mode, must be owner or group leader. * Because of lack of users file, leader=>group itself. */ - if(dir.mode!=~0 && r->perm!=dir.mode){ - if(strcmp(f->user, r->user) != 0) - if(strcmp(f->user, r->group) != 0) - return Enotowner; + if(r->d.mode != ~0 && f->mode != r->d.mode){ + if(strcmp(u, f->uid) != 0) + if(strcmp(u, f->gid) != 0){ + respond(r, Enotowner); + return; + } } /* @@ -716,204 +324,125 @@ rwstat(Fid *f) * or leader of current group and leader of new group. * Second case cannot happen, but we check anyway. */ - if(dir.gid[0]!='\0' && strcmp(r->group, dir.gid)!=0){ - if(strcmp(f->user, r->user) == 0) - // if(strcmp(f->user, dir.gid) == 0) - goto ok; - if(strcmp(f->user, r->group) == 0) - if(strcmp(f->user, dir.gid) == 0) - goto ok; - return Enotowner; - ok:; + while(r->d.gid[0] != '\0' && strcmp(f->gid, r->d.gid) != 0){ + if(strcmp(u, f->uid) == 0) + break; + if(strcmp(u, f->gid) == 0) + if(strcmp(u, r->d.gid) == 0) + break; + respond(r, Enotowner); + return; } - /* all ok; do it */ - if(dir.mode != ~0){ - dir.mode &= ~DMDIR; /* cannot change dir bit */ - dir.mode |= r->perm&DMDIR; - r->perm = dir.mode; + if(r->d.mode != ~0){ + f->mode = (r->d.mode & ~DMDIR) | (f->mode & DMDIR); + f->qid.type = 0; + if(f->mode & DMDIR) + f->qid.type |= QTDIR; + if(f->mode & DMAPPEND) + f->qid.type |= QTAPPEND; + if(f->mode & DMEXCL) + f->qid.type |= QTEXCL; } - if(dir.name[0] != '\0'){ - free(r->name); - r->name = estrdup(dir.name); + if(r->d.name[0] != '\0'){ + free(f->name); + f->name = estrdup9p(r->d.name); } - if(dir.gid[0] != '\0') - r->group = estrdup(dir.gid); - if(dir.length!=~0 && dir.length!=r->ndata){ - r->data = erealloc(r->data, dir.length); - if(r->ndata < dir.length) - memset(r->data+r->ndata, 0, dir.length-r->ndata); - r->ndata = dir.length; - } - ram[r->parent].mtime = time(0); - return 0; -} + if(r->d.length != ~0 && r->d.length != f->length) + truncfile(f, r->d.length); -uint -ramstat(Ram *r, uchar *buf, uint nbuf) -{ - int n; - Dir dir; - - dir.name = r->name; - dir.qid = r->qid; - dir.mode = r->perm; - dir.length = r->ndata; - dir.uid = r->user; - dir.gid = r->group; - dir.muid = r->muid; - dir.atime = r->atime; - dir.mtime = r->mtime; - n = convD2M(&dir, buf, nbuf); - if(n > 2) - return n; - return 0; + accessfile(f, AWRITE); + respond(r, nil); + return; + +Perm: + respond(r, Eperm); } -Fid * -newfid(int fid) +void +fscreate(Req *r) { - Fid *f, *ff; - - ff = 0; - for(f = fids; f; f = f->next) - if(f->fid == fid) - return f; - else if(!ff && !f->busy) - ff = f; - if(ff){ - ff->fid = fid; - return ff; + File *f; + int p; + + f = r->fid->file; + p = r->ifcall.perm; + if((p & DMDIR) != 0) + p = (p & ~0777) | ((p & f->mode) & 0777); + else + p = (p & ~0666) | ((p & f->mode) & 0666); + if((f = createfile(f, r->ifcall.name, r->fid->uid, p, nil)) == nil){ + responderror(r); + return; } - f = emalloc(sizeof *f); - f->ram = nil; - f->fid = fid; - f->next = fids; - fids = f; - return f; + f->atime = f->mtime = time(0); + f->aux = nil; + r->fid->file = f; + r->ofcall.qid = f->qid; + respond(r, nil); } void -io(void) +fsopen(Req *r) { - char *err, buf[40]; - int n, pid, ctl; - Fid *fid; + File *f; - pid = getpid(); - if(private){ - snprint(buf, sizeof buf, "/proc/%d/ctl", pid); - ctl = open(buf, OWRITE); - if(ctl < 0){ - fprint(2, "can't protect ramfs\n"); - }else{ - fprint(ctl, "noswap\n"); - fprint(ctl, "private\n"); - close(ctl); + f = r->fid->file; + if((f->mode & DMEXCL) != 0){ + if(f->ref > 2 && (long)((ulong)time(0)-(ulong)f->atime) < 300){ + respond(r, Elocked); + return; } } - - for(;;){ - /* - * reading from a pipe or a network device - * will give an error after a few eof reads. - * however, we cannot tell the difference - * between a zero-length read and an interrupt - * on the processes writing to us, - * so we wait for the error. - */ - n = read9pmsg(mfd[0], mdata, messagesize); - if(n < 0){ - rerrstr(buf, sizeof buf); - if(buf[0]=='\0' || strstr(buf, "hungup")) - exits(""); - error("mount read"); - } - if(n == 0) - continue; - if(convM2S(mdata, n, &thdr) == 0) - continue; - - if(debug) - fprint(2, "ramfs %d:<-%F\n", pid, &thdr); - - if(thdr.type<0 || thdr.type>=nelem(fcalls) || !fcalls[thdr.type]) - err = "bad fcall type"; - else if(((fid=newfid(thdr.fid))==nil || !fid->ram) && needfid[thdr.type]) - err = "fid not in use"; - else - err = (*fcalls[thdr.type])(fid); - if(err){ - rhdr.type = Rerror; - rhdr.ename = err; - }else{ - rhdr.type = thdr.type + 1; - rhdr.fid = thdr.fid; - } - rhdr.tag = thdr.tag; - if(debug) - fprint(2, "ramfs %d:->%F\n", pid, &rhdr);/**/ - n = convS2M(&rhdr, mdata, messagesize); - if(n == 0) - error("convS2M error on write"); - if(write(mfd[1], mdata, n) != n) - error("mount write"); + if((f->mode & DMAPPEND) == 0 && (r->ifcall.mode & OTRUNC) != 0){ + truncfile(f, 0); + accessfile(f, AWRITE); } + respond(r, nil); } -int -perm(Fid *f, Ram *r, int p) +void +fsdestroyfid(Fid *fid) { - if((p*Pother) & r->perm) - return 1; - if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm)) - return 1; - if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm)) - return 1; - return 0; + File *f; + + f = fid->file; + if(fid->omode != -1 && (fid->omode & ORCLOSE) != 0 && f != nil && f->parent != nil) + removefile(f); } void -error(char *s) +fsdestroyfile(File *f) { - fprint(2, "%s: %s: %r\n", argv0, s); - exits(s); + truncfile(f, 0); } -void * -emalloc(ulong n) +void +fsstart(Srv *) { - void *p; + char buf[40]; + int ctl; - p = malloc(n); - if(!p) - error("out of memory"); - memset(p, 0, n); - return p; + if(private){ + snprint(buf, sizeof buf, "/proc/%d/ctl", getpid()); + if((ctl = open(buf, OWRITE)) < 0) + sysfatal("can't protect memory: %r"); + fprint(ctl, "noswap\n"); + fprint(ctl, "private\n"); + close(ctl); + } } -void * -erealloc(void *p, ulong n) -{ - p = realloc(p, n); - if(!p) - error("out of memory"); - return p; -} +Srv fs = { + .open= fsopen, + .read= fsread, + .write= fswrite, + .wstat= fswstat, + .create= fscreate, + .destroyfid= fsdestroyfid, -char * -estrdup(char *q) -{ - char *p; - int n; - - n = strlen(q)+1; - p = malloc(n); - if(!p) - error("out of memory"); - memmove(p, q, n); - return p; -} + .start= fsstart, +}; void usage(void) @@ -921,3 +450,72 @@ usage(void) fprint(2, "usage: %s [-Dipsubac] [-m mountpoint] [-S srvname]\n", argv0); exits("usage"); } + +void +main(int argc, char **argv) +{ + char *srvname = nil; + char *mtpt = "/tmp"; + int mountflags; + Qid q; + + fs.tree = alloctree(nil, nil, DMDIR|0777, fsdestroyfile); + q = fs.tree->root->qid; + + mountflags = 0; + ARGBEGIN{ + case 'D': + chatty9p++; + break; + case 's': + srvname = "/srv/ramfs"; + mtpt = nil; + break; + case 'S': + srvname = EARGF(usage()); + mtpt = nil; + break; + case 'm': + mtpt = EARGF(usage()); + break; + case 'i': + fs.nopipe = 1; + srvname = nil; + mtpt = nil; + break; + case 'p': + private = 1; + break; + case 'u': + rampool.maxsize = (uintptr)~0; + break; + case 'b': + mountflags |= MBEFORE; + break; + case 'c': + mountflags |= MCREATE; + break; + case 'a': + mountflags |= MAFTER; + break; + default: + usage(); + }ARGEND; + if(argc > 0) + usage(); + + if(fs.nopipe){ + fs.infd = 0; + fs.outfd = 1; + srv(&fs); + exits(0); + } + + if(srvname == nil && mtpt == nil) + sysfatal("must specify -S, or -m option"); + + if(mountflags == 0) + mountflags = MREPL | MCREATE; + postmountsrv(&fs, srvname, mtpt, mountflags); + exits(0); +} |