ref: 9cf2807db9e8268a4dfbce19561bd712e4430a39
dir: /sub.c/
#include "all.h" extern Srv mysrv; u64 newqpath() { u64 qpath; Iobuf *sb; Super *s; s32 on, nn; s8 buf[Ddatasize-16]; sb = getbufchk(Bdsuper, Bwritable, Tdentry, Qpsuper); if(sb == nil){ panic("newqpath: sb == nil\n"); } s = (Super*)sb->d; on = snprint(buf, Ddatasize-16, "%llud", s->qidgen); qpath = s->qidgen++; nn = snprint(buf, Ddatasize-16, "%llud", s->qidgen); if(on != nn) s->size += nn-on; 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; } /* making the assumption that all allocations are not readonly */ Iobuf * allocblock(int tag, u64 qpath) { u64 blkno; Iobuf *buf; u16 len; len = blklen(tag); blkno = balloc(&frees, len); if(blkno == 0) return nil; /* the caller should trigger an Efull message */ 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); /* clear the buf to avoid leaks on reuse */ memset(buf->xiobuf, 0, len*Unit); settag(buf, tag, qpath); return buf; } /* the buf should have been wlock()'ed */ void freeblockbuf(Iobuf *buf) { if(buf->readers) panic("freeblockbuf without Bwritable"); /* clear the buf to avoid leaks on reuse */ memset(buf->xiobuf, 0, buf->len*Unit); bfree(&frees, buf->blkno, buf->len); putbuffree(buf); } /* add the block to the extents used to manage free blocks */ void freeblock(u64 blkno, 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, Bwritable, 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; Super *s; sb = getbufchk(Bdsuper, Bwritable, Tdentry, Qpsuper); if(sb == nil){ panic("fsok: sb == nil\n"); } s = (Super*)sb->d; s->fsok = ok; if(chatty9p > 1){ dprint("fsok ok %d\n", ok); showsuper(2, (u8*)s); } putbuf(sb); } void closefd(int fd) { if(fd != -1) close(fd); } void reamfile(u64 dblkno, u64 qpath, char *name, u64 size, u64 pdblkno, u64 pqpath, u64 contentblkno) { Iobuf *b; Dentry *d; b = getbuf(dblkno, Dentryunits, Bwritable, Bfreshalloc); memset(b->io, 0, Dentrysize); settag(b, Tdentry, qpath); d = b->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) d->dblocks[0] = contentblkno; putbuf(b); } /* The reamer is added to the adm group. The ctl file is owned by the ream'er and the adm group. */ char magic[] = "m[a]fs device\n"; void reamdefaults(u64 bdconfig0, u64 bdsuper0, u64 bdroot0, u64 bdconfig1, u64 bdsuper1, u64 bdroot1) { Iobuf *b; Dentry *d; char users[128+Userlen*3]; 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 /adm though as the block number is 0 */ b = getbuf(Bdmagic, Dentryunits, Bwritable, Bfreshalloc); memset(b->d, 0, Dentrysize); settag(b, Tdentry, Qpmagic); d = b->d; strncpy(d->name, "magic", 6); 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 = Qpmagic; d->qid.version = 0; d->mtime = nsec(); d->pdblkno = Bdadm; d->pqpath = Qpadm; n = snprint((s8*)d->buf, Ddatasize, "%s%llud\n", magic, Unit); d->size = n; putbuf(b); b = getbuf(Bdadm, Dentryunits, Bwritable, Bfreshalloc); memset(b->d, 0, Dentrysize); settag(b, Tdentry, Qpadm); d = b->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 = Bdroot; d->pqpath = Qproot; d->dblocks[0] = Bdconfig; d->dblocks[1] = Bdsuper; d->dblocks[2] = Bdusers; d->dblocks[3] = Bdbkp; d->dblocks[4] = Bdfrees; d->dblocks[5] = Bdctl; putbuf(b); b = getbuf(Bdbkp, Dentryunits, Bwritable, Bfreshalloc); memset(b->d, 0, Dentrysize); settag(b, Tdentry, Qpbkp); d = b->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 = Bdadm; d->pqpath = Qpadm; d->dblocks[0] = bdconfig0; d->dblocks[1] = bdsuper0; d->dblocks[2] = bdroot0; d->dblocks[3] = bdconfig1; d->dblocks[4] = bdsuper1; d->dblocks[5] = bdroot1; putbuf(b); b = getbuf(Bdusers, Dentryunits, Bwritable, Bfreshalloc); memset(b->d, 0, Dentrysize); settag(b, Tdentry, Qpusers); d = b->d; strncpy(d->name, "users", 6); 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 = Qpusers; d->qid.version = 0; d->mtime = nsec(); d->size = strlen(users)+1; d->pdblkno = Bdadm; d->pqpath = Qpadm; d->dblocks[0] = Bdusersinuse; d->dblocks[1] = Bdusersstaging; putbuf(b); b = getbuf(Bdusersinuse, Dentryunits, Bwritable, Bfreshalloc); memset(b->d, 0, Dentrysize); settag(b, Tdentry, Qpusersinuse); d = b->d; strncpy(d->name, "inuse", 6); d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qid.path = Qpusersinuse; d->qid.version = 0; d->mtime = nsec(); d->size = userslen; d->pdblkno = Bdusers; d->pqpath = Qpusers; strcpy((s8*)d->buf, users); putbuf(b); b = getbuf(Bdroot, Dentryunits, Bwritable, Bfreshalloc); memset(b->d, 0, Dentrysize); settag(b, Tdentry, Qproot); d = b->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->dblocks[0] = Bdadm; putbuf(b); reamfile(Bdconfig, Qpconfig, "config", 0, Bdadm, Qpadm, 0); reamfile(Bdctl, Qpctl, "ctl", 0, Bdadm, Qpadm, 0); reamfile(Bdfrees, Qpfrees, "frees", 0, Bdadm, Qpadm, 0); reamfile(Bdusersstaging, Qpusersstaging, "staging", 0, Bdusers, Qpusers, 0); } void superream(u64 size, u64 nblocks) { Iobuf *sbuf; Super *s; u64 nbused; nbused = Nbused; sbuf = getbuf(Bdsuper, Dentryunits, Bwritable, Bfreshalloc); if(sbuf == nil) panic("superream: sbuf == nil"); memset(sbuf->d, 0, Dentrysize); settag(sbuf, Tdentry, Qpsuper); s = (Super*)sbuf->d; strncpy(s->name, "super", 6); s->uid = s->muid = s->gid = -1; s->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); s->qid.path = Qpsuper; s->qid.version = 0; s->mtime = nsec(); s->size = 18; s->pdblkno = Bdadm; s->pqpath = Qpadm; 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.config.dest[1] = nbused+((nblocks-nbused)/2)-Bdconfig; config.super.dest[0] = nblocks-Bdsuper; config.super.dest[1] = nbused+((nblocks-nbused)/2)-Bdsuper; config.root.dest[0] = nblocks-3; config.root.dest[1] = nbused+((nblocks-nbused)/2)-3; reamfile(config.config.dest[0], Qpconfig0, "config.0", 0, Bdbkp, Qpbkp, config.config.dest[0]); reamfile(config.super.dest[0], Qpsuper0, "super.0", 0, Bdbkp, Qpbkp, config.super.dest[0]); reamfile(config.root.dest[0], Qproot0, "root.0", 0, Bdbkp, Qpbkp, config.root.dest[0]); reamfile(config.config.dest[1], Qpconfig1, "config.1", 0, Bdbkp, Qpbkp, config.config.dest[1]); reamfile(config.super.dest[1], Qpsuper1, "super.1", 0, Bdbkp, Qpbkp, config.super.dest[1]); reamfile(config.root.dest[1], Qproot1, "root.1", 0, Bdbkp, Qpbkp, config.root.dest[1]); 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]); reamdefaults(config.config.dest[0], config.super.dest[0], config.root.dest[0], config.config.dest[1], config.super.dest[1], config.root.dest[1]); 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(2, "free extents: ", &frees); if(chatty9p > 1) dprint("done\n"); /* this will enable backups */ config.config.srcbno = Bdconfig; config.super.srcbno = Bdsuper; config.root.srcbno = Bdroot; strncpy(config.service, service, Namelen); 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[Unit]; int i; u64 nblocks; nblocks = size/Unit; if(nblocks <= Nminblocks) panic("not enough space"); if(chatty9p > 1){ dprint("%s %s ream %llud bytes into %llud units of %d bytes\n", service, devfile, size, nblocks, Unit); dprint(" (dentry size: raw %d bytes)\n", Dentrysize); dprint(" (data block size: raw %d bytes, usable %d bytes)\n", Rawblocksize, Blocksize); dprint(" (name length: %d bytes)\n", Namelen); } memset(buf, 0, Unit); for(i = 0; i < Nbused; i++) devwrite(i, buf, 1); superream(size, nblocks); writeconfig(Bdconfig); 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; Super *s; s8 *rptr; if(doream) ream(size); else{ initconfig(Bdconfig); loadfrees(Bdfrees); } /* check magic */ b = getbufchk(Bdmagic, Breadonly, Tdentry, Qpmagic); if(b == nil){ panic("Invalid magic: %s",errstring[Ephase]); return; } 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 != Unit){ print("init incorrect block size Unit %llud unitsize %d\n", Unit, unitsize); panic("bad Unit != unitsize"); } putbuf(b); /* check super */ sb = getbufchk(Bdsuper, Breadonly, Tdentry, Qpsuper); if(sb == nil){ panic("Invalid super: %s",errstring[Ephase]); return; } s = (Super*)sb->io; 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); }