ref: 285644aadb1b58735651a5068703372f8fc9adac
dir: /sub.c/
#include "all.h" extern Srv mysrv; u64 newqpaths(u8 n) { u64 qpath; Iobuf *sb; Dentry *s; sb = egetmetachk(Bdsuper, Bwritable, Tdentry, Qpsuper); s = sb->d; qpath = s->qidgen; s->qidgen += n; putbuf(sb, 1); return qpath; } u64 newqpath() { return newqpaths(1); } /* * 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<strlen(n); i++) { c = *n & 0xff; if(c == 0) { if(i == 0) return 1; 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.super.dest[0] || bno == config.root.dest[0]) return 1; else return 0; } /* making the assumption that all allocations are not readonly */ Iobuf * allocblocks(u64 len, int tag, u64 qpath) { u64 blkno; Iobuf *buf; if(len > Maxdatablockunits) panic("allocblocks(): invalid len %llud tag %s qpath %llud\n", len, tagnames[tag], qpath); ualloc(&frees, len, &blkno); if(chatty9p > 1) dprint("alloc %llud\n", blkno); /* cannot do getbufchk() unless we ream the whole disk at start */ buf = getbuf(blkno, len, Bwritable, Bfreshalloc, getcallerpc(&len)); /* clear the buf to avoid leaks on reuse */ memset(buf->xiobuf, 0, len*Blocksize); if(tag == Tdata){ buf->io->len = len; buf->xiobuf64[len*Nu64perblock -1] = qpath; } settag(buf, tag, qpath); return buf; } Iobuf * allocmeta(int tag, u64 qpath) { return allocblocks(1, tag, qpath); } u8 allocdentries(u16 n, Iobuf **iobufs, u64 qpath) { u8 i, j; for(i = 0; i < n; i++){ iobufs[i] = allocblocks(1, Tdentry, qpath+i); if(iobufs[i] == nil){ for(j = 0; j < i; j++) freeblockbuf(iobufs[j]); return i; } iobufs[i]->d->qpath = qpath+i; } return i; } /* the buf should have been wlock()'ed */ void freeblockbuf(Iobuf *buf) { if(buf->readers) panic("freeblockbuf without Bwritable"); buf->tag = Tblank; /* clear the buf to avoid leaks on reuse */ memset(buf->xiobuf, 0, buf->len*Blocksize); ufree(&frees, buf->blkno, buf->len); putbuf(buf, 0); } /* add the block to the extents used to manage free blocks */ void freeblocks(u64 blkno, u64 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 = egetbufchk(blkno, len, Bwritable, tag, qpath, getcallerpc(&blkno)); 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; Dentry *s; sb = egetmetachk(Bdsuper, Bwritable, Tdentry, Qpsuper); s = sb->d; s->fsok = ok; if(chatty9p > 1){ dprint("fsok ok %d\n", ok); showsuper(2, (u8*)s); } putbuf(sb, 1); } void closefd(int fd) { if(fd != -1) close(fd); } void reamfile(u64 dblkno, u64 qpath, char *name, u64 size, u64 pdblkno, u64 pqpath, u64 preli) { Iobuf *b; Dentry *d; b = egetmeta(dblkno, Bwritable, Bfreshalloc); settag(b, Tdentry, qpath); d = b->d; USED(name); /* d->namelen = strlen(name); strcpy(d->name, name);*/ d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = qpath; d->version = 1; d->mtime = nsec(); d->size = size; d->pdblkno = pdblkno; d->pqpath = pqpath; d->preli = preli; putbuf(b, 1); } /* The reamer is added to the adm group. The ctl file is owned by the ream'er and the adm group. */ char magic[] = "mafs device\n"; void reamdefaults(u64 bdconfig0, u64 bdsuper0, u64 bdroot0) { Iobuf *b; Dentry *d; char users[128+Userlen*3], cbuf[Ddatasize]; char inle[] = "0 439 440\n\0"; char *user; int userslen, n; user = getuser(); userslen = snprint(users, 128+Userlen*3, "-1:adm:adm:%s\n" "0:none:adm:\n" /* user ID for "none" */ "9999:noworld::\n" /* conventional id for "noworld" group */ "10000:sys::\n" "10001:upas:upas:\n" /* what is this for? */ "10006:%s:%s:\n", user, user, user); /* cannot show this in /a though as the block number is 0 */ b = egetmeta(Bdmagic, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpmagic); d = b->d; // d->namelen = 5; // strncpy(d->name, "magic", 6); d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpmagic; d->version = 1; d->mtime = nsec(); d->pdblkno = Bda; d->pqpath = Qpa; d->preli = 0; n = snprint((s8*)d->buf, Ddatasize, "%s%llud\n", magic, Blocksize); d->size = n; putbuf(b, 1); b = egetmeta(Bdrootnames, Bwritable, Bfreshalloc); settag(b, Tdentry, Qprootnames); d = b->d; d->flags = Fsys|Fn; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qprootnames; d->version = 1; d->mtime = nsec(); d->pdblkno = Bdroot; d->pqpath = Qproot; d->preli = In; putbuf(b, 1); b = egetmeta(Bdrootlnames, Bwritable, Bfreshalloc); settag(b, Tdentry, Qprootlnames); d = b->d; d->flags = Fsys; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qprootlnames; d->version = 1; d->mtime = nsec(); d->pdblkno = Bdroot; d->pqpath = Qproot; d->preli = Inl; putbuf(b, 1); b = egetmeta(Bdrootlnamesextents, Bwritable, Bfreshalloc); settag(b, Tdentry, Qprootlnamesextents); d = b->d; d->flags = Fsys|Fe; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qprootlnamesextents; d->version = 1; d->mtime = nsec(); d->pdblkno = Bdroot; d->pqpath = Qproot; d->preli = Inle; d->size = sizeof inle; strcpy((s8*)d->buf, inle); putbuf(b, 1); b = egetmeta(Bdroot, Bwritable, Bfreshalloc); settag(b, Tdentry, Qproot); d = b->d; d->uid = d->muid = -1; d->gid = -1; d->mode = DMDIR | ((DMREAD|DMWRITE|DMEXEC) << 6) | ((DMREAD|DMWRITE|DMEXEC) << 3) | ((DMREAD|DMWRITE|DMEXEC) << 0); d->qpath = Qproot; d->version = 1; d->mtime = nsec(); d->dblocks[0] = Bdrootnames; d->dblocks[1] = Bdrootlnames; d->dblocks[2] = Bdrootlnamesextents; d->dblocks[3] = Bda; addname(d, -1, 0, ".n"); addname(d, -1, 1, ".nl"); addname(d, -1, 2, ".nle"); addname(d, -1, 3, "a"); putbuf(b, 1); b = egetmeta(Bdanames, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpanames); d = b->d; d->flags = Fsys|Fn; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpanames; d->version = 1; d->mtime = nsec(); d->pdblkno = Bda; d->pqpath = Qpa; d->preli = In; putbuf(b, 1); b = egetmeta(Bdalnames, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpalnames); d = b->d; d->flags = Fsys; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpalnames; d->version = 1; d->mtime = nsec(); d->pdblkno = Bda; d->pqpath = Qpa; d->preli = Inl; putbuf(b, 1); b = egetmeta(Bdalnamesextents, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpalnamesextents); d = b->d; d->flags = Fsys|Fe; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpalnamesextents; d->version = 1; d->mtime = nsec(); d->pdblkno = Bda; d->pqpath = Qpa; d->preli = Inle; d->size = sizeof inle; strcpy((s8*)d->buf, inle); putbuf(b, 1); b = egetmeta(Bda, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpa); d = b->d; d->uid = d->muid = d->gid = -1; d->mode = DMDIR | ((DMREAD|DMWRITE|DMEXEC) << 6) | ((DMREAD|DMWRITE|DMEXEC) << 3) | ((DMREAD|DMWRITE|DMEXEC) << 0); d->qpath = Qpa; d->version = 0; d->mtime = nsec(); d->pdblkno = Bdroot; d->pqpath = Qproot; d->preli = 3; d->dblocks[0] = Bdanames; d->dblocks[1] = Bdalnames; d->dblocks[2] = Bdalnamesextents; d->dblocks[3] = Bdbkp; d->dblocks[4] = Bdconfig; d->dblocks[5] = Bdctl; d->dblocks[6] = Bdfrees; d->dblocks[7] = Bdsuper; d->dblocks[8] = Bdusers; addname(d, -1, 0, ".n"); addname(d, -1, 1, ".nl"); addname(d, -1, 2, ".nle"); addname(d, -1, 3, "bkp"); addname(d, -1, 4, "config"); addname(d, -1, 5, "ctl"); addname(d, -1, 6, "frees"); addname(d, -1, 7, "super"); addname(d, -1, 8, "users"); putbuf(b, 1); b = egetmeta(Bdbkpnames, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpbkpnames); d = b->d; d->flags = Fsys|Fn; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpbkpnames; d->version = 1; d->mtime = nsec(); d->pdblkno = Bdbkp; d->pqpath = Qpbkp; d->preli = In; putbuf(b, 1); b = egetmeta(Bdbkplnames, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpbkplnames); d = b->d; d->flags = Fsys; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpbkplnames; d->version = 1; d->mtime = nsec(); d->pdblkno = Bdbkp; d->pqpath = Qpbkp; d->preli = Inl; putbuf(b, 1); b = egetmeta(Bdbkplnamesextents, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpbkplnamesextents); d = b->d; d->flags = Fsys|Fe; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpbkplnamesextents; d->version = 1; d->mtime = nsec(); d->pdblkno = Bdbkp; d->pqpath = Qpbkp; d->preli = Inle; d->size = sizeof inle; strcpy((s8*)d->buf, inle); putbuf(b, 1); b = egetmeta(Bdbkp, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpbkp); d = b->d; d->uid = d->muid = d->gid = -1; d->mode = DMDIR | ((DMREAD|DMWRITE|DMEXEC) << 6) | ((DMREAD|DMWRITE|DMEXEC) << 3) | ((DMREAD|DMWRITE|DMEXEC) << 0); d->qpath = Qpbkp; d->version = 0; d->mtime = nsec(); d->size = strlen(users)+1; d->pdblkno = Bda; d->pqpath = Qpa; d->preli = 3; d->dblocks[0] = Bdbkpnames; d->dblocks[1] = Bdbkplnames; d->dblocks[2] = Bdbkplnamesextents; d->dblocks[3] = bdconfig0; d->dblocks[4] = bdroot0; d->dblocks[5] = bdsuper0; addname(d, -1, 0, ".n"); addname(d, -1, 1, ".nl"); addname(d, -1, 2, ".nle"); addname(d, -1, 3, "config.0"); addname(d, -1, 4, "root.0"); addname(d, -1, 5, "super.0"); putbuf(b, 1); b = egetmeta(Bdusersnames, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpusersnames); d = b->d; d->flags = Fsys|Fn; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpusersnames; d->version = 1; d->mtime = nsec(); d->pdblkno = Bdusers; d->pqpath = Qpusers; d->preli = In; putbuf(b, 1); b = egetmeta(Bduserslnames, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpuserslnames); d = b->d; d->flags = Fsys; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpuserslnames; d->version = 1; d->mtime = nsec(); d->pdblkno = Bdusers; d->pqpath = Qpusers; d->preli = Inl; putbuf(b, 1); b = egetmeta(Bduserslnamesextents, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpuserslnamesextents); d = b->d; d->flags = Fsys|Fe; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpuserslnamesextents; d->version = 1; d->mtime = nsec(); d->pdblkno = Bdusers; d->pqpath = Qpusers; d->preli = Inle; d->size = sizeof inle; strcpy((s8*)d->buf, inle); putbuf(b, 1); b = egetmeta(Bdusers, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpusers); d = b->d; d->uid = d->muid = d->gid = -1; d->mode = DMDIR | ((DMREAD|DMWRITE|DMEXEC) << 6) | ((DMREAD|DMWRITE|DMEXEC) << 3) | ((DMREAD|DMWRITE|DMEXEC) << 0); d->qpath = Qpusers; d->version = 1; d->mtime = nsec(); d->pdblkno = Bda; d->pqpath = Qpa; d->preli = 8; d->dblocks[0] = Bdusersnames; d->dblocks[1] = Bduserslnames; d->dblocks[2] = Bduserslnamesextents; d->dblocks[3] = Bdusersinuse; d->dblocks[4] = Bdusersstaging; addname(d, -1, 0, ".n"); addname(d, -1, 1, ".nl"); addname(d, -1, 2, ".nle"); addname(d, -1, 3, "inuse"); addname(d, -1, 4, "staging"); putbuf(b, 1); b = egetmeta(Bdusersinuse, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpusersinuse); d = b->d; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpusersinuse; d->version = 1; d->mtime = nsec(); d->size = userslen; d->pdblkno = Bdusers; d->pqpath = Qpusers; d->preli = 3; strcpy((s8*)d->buf, users); putbuf(b, 1); b = egetmeta(Bdconfig, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpconfig); d = b->d; d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpconfig; d->version = 1; d->mtime = nsec(); memset(cbuf, 0, Ddatasize); d->size = configstr(cbuf, Ddatasize); d->pdblkno = Bda; d->pqpath = Qpa; d->preli = 4; strncpy((s8*)d->buf, cbuf, d->size); putbuf(b, 1); reamfile(Bdctl, Qpctl, "ctl", 0, Bda, Qpa, 5); reamfile(Bdfrees, Qpfrees, "frees", 0, Bda, Qpa, 6); reamfile(Bdusersstaging, Qpusersstaging, "staging", 0, Bdusers, Qpusers, 4); } void superream(u64 size, u64 nblocks) { Iobuf *sbuf; Dentry *s; sbuf = getbuf(Bdsuper, 1, Bwritable, Bfreshalloc, getcallerpc(&size)); settag(sbuf, Tdentry, Qpsuper); s = sbuf->d; s->uid = s->muid = s->gid = -1; s->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); s->qpath = Qpsuper; s->version = 1; s->mtime = nsec(); s->size = sizeof(Super); s->pdblkno = Bda; s->pqpath = Qpa; s->preli = 7; 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-Bdconfig; config.super.dest[0] = nblocks-Bdsuper; config.root.dest[0] = nblocks-3; /* this will enable backups */ config.config.srcbno = Bdconfig; config.super.srcbno = Bdsuper; config.root.srcbno = Bdroot; strncpy(config.service, service, Servicelen); reamfile(config.config.dest[0], Qpconfig0, "config.0", 0, Bdbkp, Qpbkp, 3); reamfile(config.root.dest[0], Qproot0, "root.0", 0, Bdbkp, Qpbkp, 4); reamfile(config.super.dest[0], Qpsuper0, "super.0", 0, Bdbkp, Qpbkp, 5); putbuf(sbuf, 1); if(chatty9p > 1) dprint("backup config %llud" " super %llud" " root %llud\n", config.config.dest[0], config.super.dest[0], config.root.dest[0]); reamdefaults(config.config.dest[0], config.super.dest[0], config.root.dest[0]); if(config.root.dest[0]-Nbused > 0) ufree(&frees, Nbused, config.root.dest[0]-Nbused); else if (config.root.dest[0] == Nbused) dprint("mafs: %s no free blocks: config.root.dest[0] %llud Nbused %ud Nminblocks %llud\n", service, config.root.dest[0], Nbused, Nminblocks); else panic("not enough blocks for mafs config.root.dest[0] %llud Nbused %ud Nminblocks %d\n", config.root.dest[0], Nbused, Nminblocks); if(chatty9p > 1) showextents(2, "free extents: ", &frees); if(chatty9p > 1) dprint("done\n"); fsok(0); } /* open the dev file OEXCL? cannot do exclusive use file as the fd could get invalid if no I/O is done for an extended period. */ void ream(u64 size) { char buf[Blocksize]; int i; u64 nblocks; nblocks = size/Blocksize; if(nblocks < Nminblocks) panic("not enough space"); if(chatty9p > 1){ dprint("%s %s ream %llud bytes into %llud blocks of %d bytes\n", service, devfile, size, nblocks, Blocksize); dprint(" (data block size: usable %d bytes)\n", Maxdatablocksize); dprint(" (name length: %d bytes)\n", Servicelen); } memset(buf, 0, Blocksize); for(i = 0; i < Nbused; i++) devwrite(i, buf, 1); superream(size, nblocks); 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 */ void init(int doream, u64 size) { u32 unitsize; Iobuf *sb, *b; Dentry *s; s8 *rptr; if(doream) ream(size); else{ initconfig(Bdconfig); loadfrees(); } /* check magic */ b = egetmetachk(Bdmagic, Breadonly, Tdentry, Qpmagic); if(waserror()){ putbuf(b, 0); nexterror(); } if(strncmp((s8*)b->d->buf,magic,strlen(magic)) != 0){ print("init: bad magic -%s-", (s8*)b->io+256); panic("bad magic"); } unitsize = strtoul((s8*)b->d->buf+strlen(magic), &rptr, 10); if(unitsize != Blocksize){ print("init incorrect block size Blocksize %llud unitsize %d\n", Blocksize, unitsize); panic("bad Blocksize != unitsize"); } poperror(); putbuf(b, 0); /* check super */ sb = egetmetachk(Bdsuper, Bwritable, Tdentry, Qpsuper); s = sb->d; if(config.size != size){ dprint("corrupted disk or disk size changed:" " config.size %llud size %llud\n" "This is an unrecoverable situation." " Ream the disk and start over.\n", config.size, size); panic(errstring[Edirty]); } if(s->fsok != 1){ panic("There was an unsafe shutdown:\n" " use \'disk/fsck %s\' to check the disk state.\n" " Or, use \'disk/fsok %s\' to flip the fsok flag.\n", devfile, devfile); panic(errstring[Edirty]); } s->fsok = 0; putbuf(sb, 1); shuttingdown = 0; if(doream == 0) clearfrees(); 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); }