ref: 5c21eca829380c28769f79beabb7cc51f1787f97
dir: /sub.c/
#include "all.h" extern Srv mysrv; Tlock* tlocked(Iobuf *, Dentry *d) { Tlock *t, *t1; long qpath, tim; tim = time(0); qpath = d->qid.path; t1 = 0; for(t=tlocks+NTLOCK-1; t>=tlocks; t--) { if(t->qpath == qpath) if(t->time >= tim) return 0; /* its locked */ if(!t1 && t->time < tim) t1 = t; /* steal first lock */ } if(t1) { t1->qpath = qpath; t1->time = tim + TLOCK; } /* botch * out of tlock nodes simulates * a locked file */ return t1; } u64 newqpath() { u64 qpath; Iobuf *sb; Superb *s; sb = getbufchk(Bsuper, 1, Bmod, Tdata, Qpsuper); if(sb == nil){ panic("newqpath: sb == nil\n"); } s = (Superb*)sb->io->buf; qpath = s->qidgen++; putbuf(sb); return qpath; } /* * 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 */ } u64 min(u64 a, u64 b) { if(a<b) return a; else return b; } /* identify if the block is being used as a backup block */ int isbkp(u64 bno) { if(bno == config.config.dest[0] || bno == config.config.dest[1] || bno == config.super.dest[0] || bno == config.super.dest[1] || bno == config.root.dest[0] || bno == config.root.dest[1]) return 1; else return 0; } Iobuf * allocblocks(u16 len, int flags, int tag, u64 qpath) { u64 blkno; Iobuf *buf; blkno = balloc(&frees, len); if(blkno == 0) return nil; /* the caller should trigger an Efull message */ if(chatty9p > 1) dprint("alloc %d at %llud\n", len, blkno); /* cannot do getbufchk() unless we ream the whole disk at start */ buf = getbuf(blkno, len, flags|Bmod); /* clear the buf to avoid leaks on reuse */ memset(buf->io, 0, buf->len*Rawblocksize); settag(buf, tag, qpath); return buf; } /* the buf should have been wlock()'ed */ void freeblockbuf(Iobuf *buf) { if((buf->flags&Bmod) == 0) panic("freeblockbuf without Bmod"); /* clear the buf to avoid leaks on reuse */ memset(buf->io, 0, buf->len*Rawblocksize); bfree(&frees, buf->blkno, buf->len); putbuf(buf); } /* add the block to the extents used to manage free blocks */ void freeblocks(u64 blkno, u16 len, u16 tag, u64 qpath) { Iobuf *buf; if(blkno == 0 || blkno > config.nblocks){ panic("freeblock: bad addr %llud, nblocks %llud\n", blkno, config.nblocks); return; } buf = getbufchk(blkno, len, Bmod, tag, qpath); if(buf == nil) dprint("%s",errstring[Ephase]); freeblockbuf(buf); } int Gfmt(Fmt *f1) { u16 t; t = va_arg(f1->args, u16); if(t < MAXTAG) return fmtstrcpy(f1, tagnames[t]); else return fmtprint(f1, "<badtag %d>", t); } void formatinit(void) { fmtinstall('G', Gfmt); /* print tags */ } /* should be called with wlock(t)? */ void fsok(int ok) { Iobuf *sb; Superb *s; sb = getbufchk(Bsuper, 1, Bmod, Tdata, Qpsuper); if(sb == nil){ panic("newqpath: sb == nil\n"); } s = (Superb*)sb->io->buf; s->fsok = ok; if(chatty9p > 1){ dprint("fsok ok %d\n", ok); showsuper((u8*)s); } putbuf(sb); } /* almost obsolete as all writes except for the free extents are synchronous */ void sync(void) { } void closefd(int fd) { if(fd != -1) close(fd); } /* "When we say that something was written to the disk, it should be written" Bimm is obsolete as all writes are synchronous */ void reamdata(u64 bno, u16 len, u64 qpath) { Iobuf *b; b = getbuf(bno, len, Bmod); memset(b->io, 0, len*Rawblocksize); settag(b, Tdata, qpath); putbuf(b); } void reamfile(u64 dblkno, u64 qpath, char *name, u64 size, u64 pdblkno, u64 pqpath, u64 contentblkno) { Iobuf *b; Dentry *d; u16 len; b = getbuf(dblkno, 1, Bmod); memset(b->io, 0, Rawblocksize); settag(b, Tdentry, qpath); d = &b->io->d; strcpy(d->name, name); d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qid.path = qpath; d->qid.version = 0; d->mtime = nsec(); d->size = size; d->pdblkno = pdblkno; d->pqpath = pqpath; if(contentblkno > 0){ len = (size+sizeof(Tag))/Rawblocksize; if((size+sizeof(Tag))%Rawblocksize > 0) len++; d->dspans[0] = (Spanid){contentblkno,len}; } putbuf(b); } /* TODO The reamer is added to the sys group. The ctl file is owned by the ream'er and the sys group. */ void reamdefaults(void) { Iobuf *b; Dentry *d; char users[] = "-1:adm:adm:\n" "0:none:adm:\n" /* user ID for "none" */ "9999:noworld::\n" /* conventional id for "noworld" group */ "10000:sys::\n" "10001:upas:upas:\n" "10002:bootes:bootes:\n" "10006:glenda:glenda:\n" "10007:manies::\n"; b = getbuf(Badm, 1, Bmod); memset(b->io, 0, Rawblocksize); settag(b, Tdentry, Qpadm); d = &b->io->d; strncpy(d->name, "adm", 4); d->uid = d->muid = d->gid = -1; d->mode = DMDIR | ((DMREAD|DMWRITE|DMEXEC) << 6) | ((DMREAD|DMWRITE|DMEXEC) << 3) | ((DMREAD|DMWRITE|DMEXEC) << 0); d->qid.path = Qpadm; d->qid.version = 0; d->mtime = nsec(); d->pdblkno = Broot; d->pqpath = Qproot; d->dspans[0] = (Spanid){Bbkp, 1}; d->dspans[1] = (Spanid){Bdconfig, 1}; d->dspans[2] = (Spanid){Bdctl, 1}; d->dspans[3] = (Spanid){Bdsuper, 1}; d->dspans[4] = (Spanid){Bdusers, 1}; d->dspans[5] = (Spanid){Bdfrees, 1}; putbuf(b); b = getbuf(Bbkp, 1, Bmod); memset(b->io, 0, Rawblocksize); settag(b, Tdentry, Qpbkp); d = &b->io->d; strncpy(d->name, "bkp", 4); d->uid = d->muid = d->gid = -1; d->mode = DMDIR | ((DMREAD|DMWRITE|DMEXEC) << 6) | ((DMREAD|DMWRITE|DMEXEC) << 3) | ((DMREAD|DMWRITE|DMEXEC) << 0); d->qid.path = Qpbkp; d->qid.version = 0; d->mtime = nsec(); d->size = strlen(users)+1; d->pdblkno = Badm; d->pqpath = Qpadm; d->dspans[0] = (Spanid){Bdconfig0, 1}; d->dspans[1] = (Spanid){Bdsuper0, 1}; d->dspans[2] = (Spanid){Bdroot0, 1}; d->dspans[3] = (Spanid){Bdconfig1, 1}; d->dspans[4] = (Spanid){Bdsuper1, 1}; d->dspans[5] = (Spanid){Bdroot1, 1}; putbuf(b); reamfile(Bdconfig, Qpconfig, "config", 0, Badm, Qpadm, Bconfig); reamfile(Bdctl, Qpctl, "ctl", 0, Badm, Qpadm, 0); reamfile(Bdsuper, Qpsuper, "super", 0, Badm, Qpadm, Bsuper); reamfile(Bdusers, Qpusers, "users", strlen(users)+1, Badm, Qpadm, Busers); reamfile(Bdfrees, Qpfrees, "frees", 0, Badm, Qpadm, 0); reamfile(Bdconfig0, Qpconfig0, "config.0", Blocksize, Bbkp, Qpbkp, config.config.dest[0]); reamfile(Bdsuper0, Qpsuper0, "super.0", Blocksize, Bbkp, Qpbkp, config.super.dest[0]); reamfile(Bdroot0, Qproot0, "root.0", Blocksize, Bbkp, Qpbkp, config.root.dest[0]); reamfile(Bdconfig1, Qpconfig1, "config.1", Blocksize, Bbkp, Qpbkp, config.config.dest[1]); reamfile(Bdsuper1, Qpsuper1, "super.1", Blocksize, Bbkp, Qpbkp, config.super.dest[1]); reamfile(Bdroot1, Qproot1, "root.1", Blocksize, Bbkp, Qpbkp, config.root.dest[1]); b = getbuf(Busers, 1, Bmod); if(b == nil) panic("cannot get Busers"); memset(b->io, 0, Rawblocksize); settag(b, Tdata, Qpusers); strcpy((char*)b->io->buf, users); putbuf(b); } void rootream(void) { Iobuf *b; Dentry *d; b = getbuf(Broot, 1, Bmod); if(b == nil) panic("rootream b == nil"); memset(b->io, 0, Rawblocksize); settag(b, Tdentry, Qproot); d = &b->io->d; strncpy(d->name, "/", 5); d->uid = d->muid = -1; d->gid = -1; d->mode = DMDIR | ((DMREAD|DMWRITE|DMEXEC) << 6) | ((DMREAD|DMWRITE|DMEXEC) << 3) | ((DMREAD|DMWRITE|DMEXEC) << 0); d->qid.path = Qproot; d->qid.version = 0; d->mtime = nsec(); d->dspans[0] = (Spanid){Badm, 1}; putbuf(b); } void superream(u64 size, u64 nblocks) { Iobuf *sbuf; Superb *s; u64 i, nbused; nbused = Nbused; sbuf = getbuf(Bsuper, 1, Bmod); if(sbuf == nil) panic("superream: sbuf == nil"); memset(sbuf->io, 0, Rawblocksize); settag(sbuf, Tdata, Qpsuper); s = (Superb*)sbuf->io->buf; s->qidgen = Nqidgen; s->fsok = 1; /* not bothering to ream the backup blocks, they will be overwritten almost immediately anyway */ config.size = size; config.nblocks = nblocks; config.config.dest[0] = nblocks-Bconfig; config.config.dest[1] = nbused+((nblocks-nbused)/2)-Bconfig; config.super.dest[0] = nblocks-Bsuper; config.super.dest[1] = nbused+((nblocks-nbused)/2)-Bsuper; config.root.dest[0] = nblocks-Broot; config.root.dest[1] = nbused+((nblocks-nbused)/2)-Broot; for(i=0; i<Nbkp; i++){ reamdata(config.config.dest[i], 1, Qpconfig0+3*i); reamdata(config.super.dest[i], 1, Qpsuper0+3*i); reamdata(config.root.dest[i], 1, Qproot0+3*i); } putbuf(sbuf); if(chatty9p > 1) dprint("backup config %llud %llud" " super %llud %llud" " root %llud %llud\n", config.config.dest[0], config.config.dest[1], config.super.dest[0], config.super.dest[1], config.root.dest[0], config.root.dest[1]); reamdata(Bconfig, 1, Qpconfig); reamdefaults(); rootream(); bfree(&frees, config.config.dest[1]+1, config.root.dest[0]-config.config.dest[1]-1); bfree(&frees, nbused, config.root.dest[1]-nbused); if(chatty9p > 1) showextents("free extents: ", &frees); if(chatty9p > 1) dprint("done\n"); /* this will enable backups */ config.config.srcbno = Bconfig; config.super.srcbno = Bsuper; config.root.srcbno = Broot; strncpy(config.service, service, Namelen); fsok(0); } char magic[] = "mafs device\n"; /* TODO open the dev file OEXCL? */ void ream(u64 size) { char buf[Rawblocksize]; int i; u64 nblocks; Iobuf *iob; nblocks = size/Rawblocksize; if(nblocks <= Nminblocks) panic("not enough space"); if(chatty9p > 1){ dprint("%s %s ream %llud bytes into %llud blocks\n", service, devfile, size, nblocks); dprint(" (block size: raw %d bytes, usable %d bytes)\n", Rawblocksize, Blocksize); dprint(" (name length: %d bytes)\n", Namelen); } memset(buf, 0, Rawblocksize); for(i = 0; i < Nbused; i++) devwrite(i, buf, 1); superream(size, nblocks); iob = getbuf(Bmagicb, 1, Bmod); snprint((s8*)iob->io->buf+256, Rawblocksize-256, "%s%d\n%llud\n", magic, Rawblocksize, Maxspansize); settag(iob, Tmagic, Qpmagic); putbuf(iob); writeconfig(Bconfig); fsok(1); } /* * init the devices * wipe some of the file systems, or all if ream is set * this code really assumes that only one file system exists */ /* TODO open the file OEXCL? */ u64 readbkpblock(u64 dblkno, u64 qpath) /* obsolete, using Bconfig for this info */ { Iobuf *b; Dentry *d; u64 ret; b = getbufchk(dblkno, 1, Breadonly, Tdentry, qpath); if(b == nil){ putbuf(b); panic("%s",errstring[Ephase]); return 0; } d = &b->io->d; ret = d->dspans[0].blkno; putbuf(b); return ret; } void init(int doream) { u32 rbufsize, maxspansize; u64 size; Iobuf *sb, *b; Superb *s; s8 *rptr; size = devinit(devfile); if(size == 0) panic("null size %s", devfile); if(doream) ream(size); else{ initconfig(Bconfig); loadfrees(Bdfrees); } /* check magic */ b = getbufchk(Bmagicb, 1, Breadonly, Tmagic, Qpmagic); if(b == nil){ panic("Invalid magic: %s",errstring[Ephase]); return; } if(strncmp((s8*)b->io->buf+256,magic,strlen(magic)) != 0){ print("init: bad magic -%s-", (s8*)b->io+256); panic("bad magic"); } rbufsize = strtoul((s8*)b->io->buf+256+strlen(magic), &rptr, 10); if(rbufsize != Rawblocksize){ print("init incorrect block size Rawblocksize %d rbufsize %d\n", Rawblocksize, rbufsize); panic("bad Rawblocksize != rbufsize"); } maxspansize = strtoul(rptr+1, nil, 10); if(maxspansize != Maxspansize){ print("init incorrect block size Maxspansize %llud maxspansize %ud\n", Maxspansize, maxspansize); panic("bad Maxspansize != maxspansize"); } putbuf(b); /* check super */ sb = getbufchk(Bsuper, 1, Breadonly, Tdata, Qpsuper); if(sb == nil){ panic("Invalid super: %s",errstring[Ephase]); return; } s = (Superb*)sb->io->buf; if(s->fsok != 1 || config.size != size) panic(errstring[Edirty]); s->fsok = 0; putbuf(sb); shuttingdown = 0; usersinit(); } /* * 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); }