/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "all.h" Lock wpathlock; struct { Lock flock; File* ffree; /* free file structures */ Wpath* wfree;} suballoc; enum{ Finc= 128, /* allocation chunksize for files */ Fmax= 10000, /* maximum file structures to be allocated */ Winc= 8*128, /* allocation chunksize for wpath */ Wmax= 8*10000, /* maximum wpath structures to be allocated */}; Filsys*fsstr(char *p){ Filsys *fs; for(fs=filesys; fs->name; fs++) if(strcmp(fs->name, p) == 0) return fs; return 0;} voidfileinit(Chan *cp){ File *f; Tlock *t; loop: lock(&cp->flock); f = cp->flist; if(!f) { unlock(&cp->flock); return; } cp->flist = f->next; unlock(&cp->flock); qlock(f); if(t = f->tlock) { t->time = 0; f->tlock = 0; } if(f->open & FREMOV) doremove(f, 0); freewp(f->wpath); f->open = 0; f->cp = 0; qunlock(f); goto loop;} /* * returns a locked file structure */File*filep(Chan *cp, int fid, int flag){ File *f, *prev; if(fid == NOF) return 0; loop: lock(&cp->flock); for(prev=0,f=cp->flist; f; prev=f,f=f->next) { if(f->fid != fid) continue; if(prev) { prev->next = f->next; f->next = cp->flist; cp->flist = f; } goto out; } if(flag) { f = newfp(cp); if(f) { f->fid = fid; goto out; } }else print("cannot find %p.%d (list=%p)\n", cp, fid, cp->flist); unlock(&cp->flock); return 0; out: unlock(&cp->flock); qlock(f); if(f->fid != fid) { qunlock(f); goto loop; } return f;} voidsublockinit(void){ lock(&suballoc.flock); lock(&wpathlock); conf.nfile = 0; conf.nwpath = 0; unlock(&suballoc.flock); unlock(&wpathlock);} /* * always called with cp->flock locked */File*newfp(Chan *cp){ File *f, *e; retry: lock(&suballoc.flock); f = suballoc.ffree; if(f != nil){ suballoc.ffree = f->list; unlock(&suballoc.flock); f->list = 0; f->cp = cp; f->next = cp->flist; f->wpath = 0; f->tlock = 0; f->dslot = 0; f->doffset = 0; f->uid = 0; f->cuid = 0; cp->flist = f; return f; } unlock(&suballoc.flock); if(conf.nfile > Fmax){ print("%d: out of files\n", cp->chan); return 0; } /* * create a few new files */ f = malloc(Finc*sizeof(*f)); memset(f, 0, Finc*sizeof(*f)); lock(&suballoc.flock); for(e = f+Finc; f < e; f++){ qlock(f); qunlock(f); f->list = suballoc.ffree; suballoc.ffree = f; } conf.nfile += Finc; unlock(&suballoc.flock); goto retry;} voidfreefp(File *fp){ Chan *cp; File *f, *prev; if(!fp || !(cp = fp->cp)) return; authfree(fp); lock(&cp->flock); for(prev=0,f=cp->flist; f; prev=f,f=f->next) { if(f != fp) continue; if(prev) prev->next = f->next; else cp->flist = f->next; f->cp = 0; lock(&suballoc.flock); f->list = suballoc.ffree; suballoc.ffree = f; unlock(&suballoc.flock); break; } unlock(&cp->flock);} Wpath*newwp(void){ Wpath *w, *e; retry: lock(&wpathlock); w = suballoc.wfree; if(w != nil){ suballoc.wfree = w->list; unlock(&wpathlock); memset(w, 0, sizeof(*w)); w->refs = 1; w->up = 0; return w; } unlock(&wpathlock); if(conf.nwpath > Wmax){ print("out of wpaths\n"); return 0; } /* * create a few new wpaths */ w = malloc(Winc*sizeof(*w)); memset(w, 0, Winc*sizeof(*w)); lock(&wpathlock); for(e = w+Winc; w < e; w++){ w->list = suballoc.wfree; suballoc.wfree = w; } conf.nwpath += Winc; unlock(&wpathlock); goto retry;} /* * increment the references for the whole path */Wpath*getwp(Wpath *w){ Wpath *nw; lock(&wpathlock); for(nw = w; nw; nw=nw->up) nw->refs++; unlock(&wpathlock); return w;} /* * decrement the reference for each element of the path */voidfreewp(Wpath *w){ lock(&wpathlock); for(; w; w=w->up){ w->refs--; if(w->refs == 0){ w->list = suballoc.wfree; suballoc.wfree = w; } } unlock(&wpathlock);} /* * decrement the reference for just this element */voidputwp(Wpath *w){ lock(&wpathlock); w->refs--; if(w->refs == 0){ w->list = suballoc.wfree; suballoc.wfree = w; } unlock(&wpathlock);} intiaccess(File *f, Dentry *d, int m){ if(wstatallow) return 0; /* * owner is next */ if(f->uid == d->uid) if((m<<6) & d->mode) return 0; /* * group membership is hard */ if(ingroup(f->uid, d->gid)) if((m<<3) & d->mode) return 0; /* * other access for everyone except members of group 9999 */ if(m & d->mode){ /* * walk directories regardless. * otherwise its impossible to get * from the root to noworld's directories. */ if((d->mode & DDIR) && (m == DEXEC)) return 0; if(!ingroup(f->uid, 9999)) return 0; } return 1;} Tlock*tlocked(Iobuf *p, Dentry *d){ Tlock *t, *t1; long qpath, tim; Device dev; tim = time(0); qpath = d->qid.path; dev = p->dev; t1 = 0; for(t=tlocks+NTLOCK-1; t>=tlocks; t--) { if(t->qpath == qpath) if(t->time >= tim) if(devcmp(t->dev, dev) == 0) return 0; /* its locked */ if(!t1 && t->time < tim) t1 = t; /* steal first lock */ } if(t1) { t1->dev = dev; t1->qpath = qpath; t1->time = tim + TLOCK; } /* botch * out of tlock nodes simulates * a locked file */ return t1;} Qidnewqid(Device dev){ Iobuf *p; Superb *sb; Qid qid; p = getbuf(dev, superaddr(dev), Bread|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("newqid: super block"); sb = (Superb*)p->iobuf; sb->qidgen++; qid.path = sb->qidgen; qid.vers = 0; qid.type = 0; putbuf(p); return qid;} /* * what are legal characters in a name? * only disallow control characters. * a) utf avoids control characters. * b) '/' may not be the separator */intcheckname(char *n){ int i, c; for(i=0; i<NAMELEN; i++) { c = *n & 0xff; if(c == 0) { if(i == 0) return 1; memset(n, 0, NAMELEN-i); return 0; } if(c <= 040) return 1; n++; } return 1; /* too long */} voidbfree(Device dev, long addr, int d){ Iobuf *p; long a; int i; if(!addr) return; if(d > 0) { d--; p = getbuf(dev, addr, Bread); if(p) { for(i=INDPERBUF-1; i>=0; i--) { a = ((long*)p->iobuf)[i]; bfree(dev, a, d); } putbuf(p); } } /* * stop outstanding i/o */ p = getbuf(dev, addr, Bprobe); if(p) { p->flags &= ~(Bmod|Bimm); putbuf(p); } /* * dont put written worm * blocks into free list */ if(nofree(dev, addr)) return; p = getbuf(dev, superaddr(dev), Bread|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("bfree: super block"); addfree(dev, addr, (Superb*)p->iobuf); putbuf(p);} longballoc(Device dev, int tag, long qid){ Iobuf *bp, *p; Superb *sb; long a; int n; p = getbuf(dev, superaddr(dev), Bread|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("balloc: super block"); sb = (Superb*)p->iobuf; loop: n = --sb->fbuf.nfree; sb->tfree--; if(n < 0 || n >= FEPERBUF) panic("balloc: bad freelist"); a = sb->fbuf.free[n]; if(n <= 0) { if(a == 0) { sb->tfree = 0; sb->fbuf.nfree = 1; if(devgrow(dev, sb)) goto loop; putbuf(p); return 0; } bp = getbuf(dev, a, Bread); if(!bp || checktag(bp, Tfree, QPNONE)) { if(bp) putbuf(bp); putbuf(p); return 0; } memmove(&sb->fbuf, bp->iobuf, (FEPERBUF+1)*sizeof(long)); putbuf(bp); } bp = getbuf(dev, a, Bmod); memset(bp->iobuf, 0, RBUFSIZE); settag(bp, tag, qid); if(tag == Tind1 || tag == Tind2 || tag == Tdir) bp->flags |= Bimm; putbuf(bp); putbuf(p); return a;} voidaddfree(Device dev, long addr, Superb *sb){ int n; Iobuf *p; if(addr >= sb->fsize){ print("addfree: bad addr %lux\n", addr); return; } n = sb->fbuf.nfree; if(n < 0 || n > FEPERBUF) panic("addfree: bad freelist");Lines 1–500 of 699. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "all.h" Lock wpathlock; struct { Lock flock; File* ffree; /* free file structures */ Wpath* wfree; } suballoc; enum{ Finc= 128, /* allocation chunksize for files */ Fmax= 10000, /* maximum file structures to be allocated */ Winc= 8*128, /* allocation chunksize for wpath */ Wmax= 8*10000, /* maximum wpath structures to be allocated */ }; Filsys* fsstr(char *p) { Filsys *fs; for(fs=filesys; fs->name; fs++) if(strcmp(fs->name, p) == 0) return fs; return 0; } void fileinit(Chan *cp) { File *f; Tlock *t; loop: lock(&cp->flock); f = cp->flist; if(!f) { unlock(&cp->flock); return; } cp->flist = f->next; unlock(&cp->flock); qlock(f); if(t = f->tlock) { t->time = 0; f->tlock = 0; } if(f->open & FREMOV) doremove(f, 0); freewp(f->wpath); f->open = 0; f->cp = 0; qunlock(f); goto loop; } /* * returns a locked file structure */ File* filep(Chan *cp, int fid, int flag) { File *f, *prev; if(fid == NOF) return 0; loop: lock(&cp->flock); for(prev=0,f=cp->flist; f; prev=f,f=f->next) { if(f->fid != fid) continue; if(prev) { prev->next = f->next; f->next = cp->flist; cp->flist = f; } goto out; } if(flag) { f = newfp(cp); if(f) { f->fid = fid; goto out; } } else print("cannot find %p.%d (list=%p)\n", cp, fid, cp->flist); unlock(&cp->flock); return 0; out: unlock(&cp->flock); qlock(f); if(f->fid != fid) { qunlock(f); goto loop; } return f; } void sublockinit(void) { lock(&suballoc.flock); lock(&wpathlock); conf.nfile = 0; conf.nwpath = 0; unlock(&suballoc.flock); unlock(&wpathlock); } /* * always called with cp->flock locked */ File* newfp(Chan *cp) { File *f, *e; retry: lock(&suballoc.flock); f = suballoc.ffree; if(f != nil){ suballoc.ffree = f->list; unlock(&suballoc.flock); f->list = 0; f->cp = cp; f->next = cp->flist; f->wpath = 0; f->tlock = 0; f->dslot = 0; f->doffset = 0; f->uid = 0; f->cuid = 0; cp->flist = f; return f; } unlock(&suballoc.flock); if(conf.nfile > Fmax){ print("%d: out of files\n", cp->chan); return 0; } /* * create a few new files */ f = malloc(Finc*sizeof(*f)); memset(f, 0, Finc*sizeof(*f)); lock(&suballoc.flock); for(e = f+Finc; f < e; f++){ qlock(f); qunlock(f); f->list = suballoc.ffree; suballoc.ffree = f; } conf.nfile += Finc; unlock(&suballoc.flock); goto retry; } void freefp(File *fp) { Chan *cp; File *f, *prev; if(!fp || !(cp = fp->cp)) return; authfree(fp); lock(&cp->flock); for(prev=0,f=cp->flist; f; prev=f,f=f->next) { if(f != fp) continue; if(prev) prev->next = f->next; else cp->flist = f->next; f->cp = 0; lock(&suballoc.flock); f->list = suballoc.ffree; suballoc.ffree = f; unlock(&suballoc.flock); break; } unlock(&cp->flock); } Wpath* newwp(void) { Wpath *w, *e; retry: lock(&wpathlock); w = suballoc.wfree; if(w != nil){ suballoc.wfree = w->list; unlock(&wpathlock); memset(w, 0, sizeof(*w)); w->refs = 1; w->up = 0; return w; } unlock(&wpathlock); if(conf.nwpath > Wmax){ print("out of wpaths\n"); return 0; } /* * create a few new wpaths */ w = malloc(Winc*sizeof(*w)); memset(w, 0, Winc*sizeof(*w)); lock(&wpathlock); for(e = w+Winc; w < e; w++){ w->list = suballoc.wfree; suballoc.wfree = w; } conf.nwpath += Winc; unlock(&wpathlock); goto retry; } /* * increment the references for the whole path */ Wpath* getwp(Wpath *w) { Wpath *nw; lock(&wpathlock); for(nw = w; nw; nw=nw->up) nw->refs++; unlock(&wpathlock); return w; } /* * decrement the reference for each element of the path */ void freewp(Wpath *w) { lock(&wpathlock); for(; w; w=w->up){ w->refs--; if(w->refs == 0){ w->list = suballoc.wfree; suballoc.wfree = w; } } unlock(&wpathlock); } /* * decrement the reference for just this element */ void putwp(Wpath *w) { lock(&wpathlock); w->refs--; if(w->refs == 0){ w->list = suballoc.wfree; suballoc.wfree = w; } unlock(&wpathlock); } int iaccess(File *f, Dentry *d, int m) { if(wstatallow) return 0; /* * owner is next */ if(f->uid == d->uid) if((m<<6) & d->mode) return 0; /* * group membership is hard */ if(ingroup(f->uid, d->gid)) if((m<<3) & d->mode) return 0; /* * other access for everyone except members of group 9999 */ if(m & d->mode){ /* * walk directories regardless. * otherwise its impossible to get * from the root to noworld's directories. */ if((d->mode & DDIR) && (m == DEXEC)) return 0; if(!ingroup(f->uid, 9999)) return 0; } return 1; } Tlock* tlocked(Iobuf *p, Dentry *d) { Tlock *t, *t1; long qpath, tim; Device dev; tim = time(0); qpath = d->qid.path; dev = p->dev; t1 = 0; for(t=tlocks+NTLOCK-1; t>=tlocks; t--) { if(t->qpath == qpath) if(t->time >= tim) if(devcmp(t->dev, dev) == 0) return 0; /* its locked */ if(!t1 && t->time < tim) t1 = t; /* steal first lock */ } if(t1) { t1->dev = dev; t1->qpath = qpath; t1->time = tim + TLOCK; } /* botch * out of tlock nodes simulates * a locked file */ return t1; } Qid newqid(Device dev) { Iobuf *p; Superb *sb; Qid qid; p = getbuf(dev, superaddr(dev), Bread|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("newqid: super block"); sb = (Superb*)p->iobuf; sb->qidgen++; qid.path = sb->qidgen; qid.vers = 0; qid.type = 0; putbuf(p); return qid; } /* * what are legal characters in a name? * only disallow control characters. * a) utf avoids control characters. * b) '/' may not be the separator */ int checkname(char *n) { int i, c; for(i=0; i<NAMELEN; i++) { c = *n & 0xff; if(c == 0) { if(i == 0) return 1; memset(n, 0, NAMELEN-i); return 0; } if(c <= 040) return 1; n++; } return 1; /* too long */ } void bfree(Device dev, long addr, int d) { Iobuf *p; long a; int i; if(!addr) return; if(d > 0) { d--; p = getbuf(dev, addr, Bread); if(p) { for(i=INDPERBUF-1; i>=0; i--) { a = ((long*)p->iobuf)[i]; bfree(dev, a, d); } putbuf(p); } } /* * stop outstanding i/o */ p = getbuf(dev, addr, Bprobe); if(p) { p->flags &= ~(Bmod|Bimm); putbuf(p); } /* * dont put written worm * blocks into free list */ if(nofree(dev, addr)) return; p = getbuf(dev, superaddr(dev), Bread|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("bfree: super block"); addfree(dev, addr, (Superb*)p->iobuf); putbuf(p); } long balloc(Device dev, int tag, long qid) { Iobuf *bp, *p; Superb *sb; long a; int n; p = getbuf(dev, superaddr(dev), Bread|Bmod); if(!p || checktag(p, Tsuper, QPSUPER)) panic("balloc: super block"); sb = (Superb*)p->iobuf; loop: n = --sb->fbuf.nfree; sb->tfree--; if(n < 0 || n >= FEPERBUF) panic("balloc: bad freelist"); a = sb->fbuf.free[n]; if(n <= 0) { if(a == 0) { sb->tfree = 0; sb->fbuf.nfree = 1; if(devgrow(dev, sb)) goto loop; putbuf(p); return 0; } bp = getbuf(dev, a, Bread); if(!bp || checktag(bp, Tfree, QPNONE)) { if(bp) putbuf(bp); putbuf(p); return 0; } memmove(&sb->fbuf, bp->iobuf, (FEPERBUF+1)*sizeof(long)); putbuf(bp); } bp = getbuf(dev, a, Bmod); memset(bp->iobuf, 0, RBUFSIZE); settag(bp, tag, qid); if(tag == Tind1 || tag == Tind2 || tag == Tdir) bp->flags |= Bimm; putbuf(bp); putbuf(p); return a; } void addfree(Device dev, long addr, Superb *sb) { int n; Iobuf *p; if(addr >= sb->fsize){ print("addfree: bad addr %lux\n", addr); return; } n = sb->fbuf.nfree; if(n < 0 || n > FEPERBUF) panic("addfree: bad freelist");