ref: 80e6c118c65b013bde24f8b9c95881c0e3a73d3e
dir: /sub.c/
#include "all.h" extern Srv mysrv; u64 newqpath() { u64 qpath; Iobuf *sb; Dentry *s; s32 on, nn; s8 buf[Ddatasize-16]; sb = getmetachk(Bdsuper, Bwritable, Tdentry, Qpsuper); if(sb == nil){ panic("newqpath: sb == nil\n"); } s = (Dentry*)sb->new; 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, 1); 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.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 %ud tag %s qpath %llud\n", len, tagnames[tag], qpath); blkno = balloc(&frees, len); 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*Blocksize); if(tag == Tdata){ buf->io->len = len; buf->xiobuf64[len*Nu64perblock -1] = qpath; }else recentmetadata(buf->m, &buf->cur, &buf->new); settag(buf, tag, qpath); return buf; } Iobuf * allocmeta(int tag, u64 qpath) { Iobuf *b; b = allocblocks(Metadataunits, tag, qpath); if(b == nil) panic("out of free blocks\n"); b->new->verd++; return b; } /* 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); bfree(&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 = getbufchk(blkno, len, 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; Dentry *s; sb = getmetachk(Bdsuper, Bwritable, Tdentry, Qpsuper); if(sb == nil){ panic("fsok: sb == nil\n"); } s = (Dentry*)sb->new; 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) { Iobuf *b; Dentry *d; b = getmeta(dblkno, Bwritable, Bfreshalloc); if(b == nil) panic("reamfile dblkno %llud b == nil\n", dblkno); settag(b, Tdentry, qpath); d = (Dentry*)b->new; 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 = 0; d->mtime = nsec(); d->size = size; d->pdblkno = pdblkno; d->pqpath = pqpath; 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[] = "m[a]fs device\n"; void reamdefaults(u64 bdconfig0, u64 bdsuper0, u64 bdroot0) { 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 = getmeta(Bdmagic, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpmagic); d = (Dentry*)b->new; d->namelen = 5; 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->qpath = Qpmagic; d->version = 0; d->mtime = nsec(); d->pdblkno = Bdadm; d->pqpath = Qpadm; n = snprint((s8*)d->buf, Ddatasize, "%s%llud\n", magic, Blocksize); d->size = n; putbuf(b, 1); b = getmeta(Bdadm, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpadm); d = (Dentry*)b->new; d->namelen = 3; 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->qpath = Qpadm; d->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, 1); b = getmeta(Bdbkp, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpbkp); d = (Dentry*)b->new; d->namelen = 3; 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->qpath = Qpbkp; d->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; putbuf(b, 1); b = getmeta(Bdusers, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpusers); d = (Dentry*)b->new; d->namelen = 5; 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->qpath = Qpusers; d->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, 1); b = getmeta(Bdusersinuse, Bwritable, Bfreshalloc); settag(b, Tdentry, Qpusersinuse); d = (Dentry*)b->new; d->namelen = 5; strncpy(d->name, "inuse", 6); d->uid = d->muid = d->gid = -1; d->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); d->qpath = Qpusersinuse; d->version = 0; d->mtime = nsec(); d->size = userslen; d->pdblkno = Bdusers; d->pqpath = Qpusers; strcpy((s8*)d->buf, users); putbuf(b, 1); b = getmeta(Bdroot, Bwritable, Bfreshalloc); settag(b, Tdentry, Qproot); d = (Dentry*)b->new; d->namelen = 1; 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->qpath = Qproot; d->version = 0; d->mtime = nsec(); d->dblocks[0] = Bdadm; putbuf(b, 1); reamfile(Bdconfig, Qpconfig, "config", 0, Bdadm, Qpadm); reamfile(Bdctl, Qpctl, "ctl", 0, Bdadm, Qpadm); reamfile(Bdfrees, Qpfrees, "frees", 0, Bdadm, Qpadm); reamfile(Bdusersstaging, Qpusersstaging, "staging", 0, Bdusers, Qpusers); } void superream(u64 size, u64 nblocks) { Iobuf *sbuf; Dentry *s; u64 nbused; nbused = Nbused; sbuf = getbuf(Bdsuper, Metadataunits, Bwritable, Bfreshalloc); if(sbuf == nil) panic("superream: sbuf == nil"); sbuf->cur = sbuf->new = (Metadataunit*)sbuf->m; settag(sbuf, Tdentry, Qpsuper); s = (Dentry*)sbuf->new; s->verd++; s->namelen = 5; strncpy(s->name, "super", 6); s->uid = s->muid = s->gid = -1; s->mode = ((DMREAD) << 6) | ((DMREAD) << 3) | ((DMREAD) << 0); s->qpath = Qpsuper; s->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.super.dest[0] = nblocks-Bdsuper; config.root.dest[0] = nblocks-6; /* this will enable backups */ config.config.srcbno = Bdconfig; config.super.srcbno = Bdsuper; config.root.srcbno = Bdroot; strncpy(config.service, service, Namelen); reamfile(config.config.dest[0], Qpconfig0, "config.0", 0, Bdbkp, Qpbkp); reamfile(config.super.dest[0], Qpsuper0, "super.0", 0, Bdbkp, Qpbkp); reamfile(config.root.dest[0], Qproot0, "root.0", 0, Bdbkp, Qpbkp); 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) bfree(&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 %llud Nminblocks %llud\n", service, config.root.dest[0], nbused, Nminblocks); else panic("not enough blocks for mafs config.root.dest[0] %llud nbused %llud 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(" (dentry size: raw %d bytes)\n", Metadatablocksize); dprint(" (data block size: usable %d bytes)\n", Maxdatablocksize); dprint(" (name length: %d bytes)\n", Namelen); } memset(buf, 0, Blocksize); 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; Dentry *s; s8 *rptr; if(doream) ream(size); else{ initconfig(Bdconfig); loadfrees(Bdfrees); } /* check magic */ b = getmetachk(Bdmagic, Breadonly, Tdentry, Qpmagic); if(b == nil){ panic("Invalid magic: %s",errstring[Ephase]); return; } if(strncmp((s8*)((Dentry*)b->cur)->buf,magic,strlen(magic)) != 0){ print("init: bad magic -%s-", (s8*)b->io+256); panic("bad magic"); } unitsize = strtoul((s8*)((Dentry*)b->cur)->buf+strlen(magic), &rptr, 10); if(unitsize != Blocksize){ print("init incorrect block size Blocksize %llud unitsize %d\n", Blocksize, unitsize); panic("bad Blocksize != unitsize"); } putbuf(b, 0); /* check super */ sb = getmetachk(Bdsuper, Bwritable, Tdentry, Qpsuper); if(sb == nil){ panic("Invalid super: %s",errstring[Ephase]); return; } s = (Dentry*)sb->new; if(s->fsok != 1 || config.size != size) panic(errstring[Edirty]); s->fsok = 0; putbuf(sb, 1); 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); }