Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#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");
        if(n >= FEPERBUF) {
                p = getbuf(dev, addr, Bmod);
                if(p == 0)
                        panic("addfree: getbuf");
                memmove(p->iobuf, &sb->fbuf, (FEPERBUF+1)*sizeof(long));
                settag(p, Tfree, QPNONE);
                putbuf(p);
                n = 0;
        }
        sb->fbuf.free[n++] = addr;
        sb->fbuf.nfree = n;
        sb->tfree++;
        if(addr >= sb->fsize)
                sb->fsize = addr+1;
}

int
Cfmt(Fmt *f1)
{
        Chan *cp;

        cp = va_arg(f1->args, Chan*);
        return fmtprint(f1, "C%d.%.3d", cp->type, cp->chan);
}

int
Dfmt(Fmt *f1)
{
        Device d;

        d = va_arg(f1->args, Device);
        return fmtprint(f1, "D%d.%d.%d.%d", d.type, d.ctrl, d.unit, d.part);
}

int
Afmt(Fmt *f1)
{
        Filta a;

        a = va_arg(f1->args, Filta);
        return fmtprint(f1, "%6lud %6lud %6lud",
                fdf(a.f->filter[0], a.scale*60),
                fdf(a.f->filter[1], a.scale*600),
                fdf(a.f->filter[2], a.scale*6000));
}

int
Gfmt(Fmt *f1)
{
        int t;

        t = va_arg(f1->args, int);
        if(t >= 0 && t < MAXTAG)
                return fmtstrcpy(f1, tagnames[t]);
        else
                return fmtprint(f1, "<badtag %d>", t);
}

void
formatinit(void)
{

        fmtinstall('C', Cfmt);  /* print channels */
        fmtinstall('D', Dfmt);  /* print devices */
        fmtinstall('A', Afmt);  /* print filters */
        fmtinstall('G', Gfmt);  /* print tags */
        fmtinstall('T', Tfmt);  /* print times */
        fmtinstall('O', ofcallfmt);     /* print old fcalls */
}
int
devcmp(Device d1, Device d2)
{

        if(d1.type == d2.type)
        if(d1.ctrl == d2.ctrl)
        if(d1.unit == d2.unit)
        if(d1.part == d2.part)
                return 0;
        return 1;
}

void
rootream(Device dev, long addr)
{
        Iobuf *p;
        Dentry *d;

        p = getbuf(dev, addr, Bmod|Bimm);
        memset(p->iobuf, 0, RBUFSIZE);
        settag(p, Tdir, QPROOT);
        d = getdir(p, 0);
        strcpy(d->name, "/");
        d->uid = -1;
        d->gid = -1;
        d->mode = DALLOC | DDIR |
                ((DREAD|DWRITE|DEXEC) << 6) |
                ((DREAD|DWRITE|DEXEC) << 3) |
                ((DREAD|DWRITE|DEXEC) << 0);
        d->qid = QID9P1(QPROOT|QPDIR,0);
        d->atime = time(0);
        d->mtime = d->atime;
        putbuf(p);
}

int
superok(Device dev, long addr, int set)
{
        Iobuf *p;
        Superb *s;
        int ok;

        p = getbuf(dev, addr, Bread|Bmod|Bimm);
        s = (Superb*)p->iobuf;
        ok = s->fsok;
        s->fsok = set;
        putbuf(p);
        return ok;
}

void
superream(Device dev, long addr)
{
        Iobuf *p;
        Superb *s;
        long i;

        p = getbuf(dev, addr, Bmod|Bimm);
        memset(p->iobuf, 0, RBUFSIZE);
        settag(p, Tsuper, QPSUPER);

        s = (Superb*)p->iobuf;
        s->fstart = 1;
        s->fsize = devsize(dev);
        s->fbuf.nfree = 1;
        s->qidgen = 10;
        for(i=s->fsize-1; i>=addr+2; i--)
                addfree(dev, i, s);
        putbuf(p);
}

/*
 * returns 1 if n is prime
 * used for adjusting lengths
 * of hashing things.
 * there is no need to be clever
 */
int
prime(long n)
{
        long i;

        if((n%2) == 0)
                return 0;
        for(i=3;; i+=2) {
                if((n%i) == 0)
                        return 0;
                if(i*i >= n)
                        return 1;
        }
}

void
hexdump(void *a, int n)
{
        char s1[30], s2[4];
        uchar *p;
        int i;

        p = a;
        s1[0] = 0;
        for(i=0; i<n; i++) {
                sprint(s2, " %.2ux", p[i]);
                strcat(s1, s2);
                if((i&7) == 7) {
                        print("%s\n", s1);
                        s1[0] = 0;
                }
        }
        if(s1[0])
                print("%s\n", s1);
}

long
qidpathgen(Device *dev)
{
        Iobuf *p;
        Superb *sb;
        long path;

        p = getbuf(*dev, superaddr((*dev)), Bread|Bmod);
        if(!p || checktag(p, Tsuper, QPSUPER))
                panic("newqid: super block");
        sb = (Superb*)p->iobuf;
        sb->qidgen++;
        path = sb->qidgen;
        putbuf(p);
        return path;
}