ref: ac3ddb687ea2f6dde774292d1146210705821bbc
dir: /ream.c/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <avl.h>
#include "dat.h"
#include "fns.h"
enum {
Qmainroot,
Qadmroot,
Qadmuser,
Nreamqid,
};
char *defaultusers ="-1:adm::%s\n0:none::\n";
static void
fillxdir(Xdir *d, vlong qid, char *name, int type, int mode)
{
memset(d, 0, sizeof(Xdir));
d->qid = (Qid){qid, 0, type};
d->mode = mode;
d->atime = 0;
d->mtime = 0;
d->length = 0;
d->name = name;
d->uid = -1;
d->gid = -1;
d->muid = 0;
}
static void
initadm(Blk *r, Blk *u, int nu)
{
char *p, kbuf[Keymax], vbuf[Inlmax];
Kvp kv;
Xdir d;
/* nb: values must be inserted in key order */
kv.k = kbuf;
kv.nk = Offksz;
kv.v = vbuf;
kv.nv = Ptrsz;
kbuf[0] = Kdat;
PACK64(kbuf+1, (uvlong)Qadmuser);
PACK64(kbuf+9, 0ULL);
packbp(kv.v, kv.nv, &u->bp);
setval(r, &kv);
fillxdir(&d, Qadmuser, "users", QTFILE, 0664);
d.length = nu;
if(dir2kv(Qadmroot, &d, &kv, vbuf, sizeof(vbuf)) == -1)
sysfatal("ream: pack users: %r");
setval(r, &kv);
fillxdir(&d, Qadmroot, "", QTDIR, DMDIR|0775);
if(dir2kv(-1, &d, &kv, vbuf, sizeof(vbuf)) == -1)
sysfatal("ream: pack root: %r");
setval(r, &kv);
if((p = packsuper(kbuf, sizeof(kbuf), 0)) == nil)
sysfatal("ream: pack super");
kv.k = kbuf;
kv.nk = p - kbuf;
if((p = packdkey(vbuf, sizeof(vbuf), -1, "")) == nil)
sysfatal("ream: pack super");
kv.v = vbuf;
kv.nv = p - vbuf;
setval(r, &kv);
}
static void
initroot(Blk *r)
{
char *p, kbuf[Keymax], vbuf[Inlmax];
Kvp kv;
Xdir d;
/* nb: values must be inserted in key order */
fillxdir(&d, Qmainroot, "", QTDIR, DMDIR|0775);
if(dir2kv(-1, &d, &kv, vbuf, sizeof(vbuf)) == -1)
sysfatal("ream: pack root: %r");
setval(r, &kv);
if((p = packsuper(kbuf, sizeof(kbuf), 0)) == nil)
sysfatal("ream: pack super");
kv.k = kbuf;
kv.nk = p - kbuf;
if((p = packdkey(vbuf, sizeof(vbuf), -1, "")) == nil)
sysfatal("ream: pack super");
kv.v = vbuf;
kv.nv = p - vbuf;
setval(r, &kv);
}
static void
initsnap(Blk *s, Blk *r, Blk *a)
{
char *p, kbuf[Keymax], vbuf[Treesz];
Tree t;
Kvp kv;
p = packlabel(kbuf, sizeof(kbuf), "adm");
kv.k = kbuf;
kv.nk = p - kbuf;
p = packsnap(vbuf, sizeof(vbuf), 1);
kv.v = vbuf;
kv.nv = p - vbuf;
setval(s, &kv);
p = packlabel(kbuf, sizeof(kbuf), "empty");
kv.k = kbuf;
kv.nk = p - kbuf;
p = packsnap(vbuf, sizeof(vbuf), 0);
kv.v = vbuf;
kv.nv = p - vbuf;
setval(s, &kv);
p = packlabel(kbuf, sizeof(kbuf), "main");
kv.k = kbuf;
kv.nk = p - kbuf;
p = packsnap(vbuf, sizeof(vbuf), 0);
kv.v = vbuf;
kv.nv = p - vbuf;
setval(s, &kv);
p = packsnap(kbuf, sizeof(kbuf), 0);
kv.k = kbuf;
kv.nk = p - kbuf;
memset(&t, 0, sizeof(Tree));
t.nsucc = 1;
t.nlbl = 2;
t.ht = 1;
t.gen = fs->nextgen++;
t.prev = -1ULL;
t.bp = r->bp;
p = packtree(vbuf, sizeof(vbuf), &t);
kv.v = vbuf;
kv.nv = p - vbuf;
setval(s, &kv);
p = packsnap(kbuf, sizeof(kbuf), 1);
kv.k = kbuf;
kv.nk = p - kbuf;
memset(&t, 0, sizeof(Tree));
t.nsucc = 0;
t.nlbl = 1;
t.ht = 1;
t.gen = fs->nextgen++;
t.prev = -1ULL;
t.bp = a->bp;
p = packtree(vbuf, sizeof(vbuf), &t);
kv.v = vbuf;
kv.nv = p - vbuf;
setval(s, &kv);
}
static void
initarena(Arena *a, Fshdr *fi, vlong start, vlong asz)
{
vlong addr, bo, bh;
char *p;
Blk *b;
b = cachepluck();
addr = start+Blksz; /* arena loghder */
a->loghd.addr = -1;
a->loghd.hash = -1;
a->loghd.gen = -1;
memset(b->buf, 0, sizeof(b->buf));
b->type = Tlog;
b->bp.addr = addr;
b->logsz = 32;
b->data = b->buf + Loghdsz;
setflag(b, Bdirty);
p = b->data + Loghashsz;
PACK64(p, addr|LogFree); p += 8; /* addr */
PACK64(p, asz-Blksz); p += 8; /* len */
PACK64(p, b->bp.addr|LogAlloc); p += 8; /* addr */
PACK64(p, Blksz); p += 8; /* len */
PACK64(p, (uvlong)LogEnd); /* done */
finalize(b);
if(syncblk(b) == -1)
sysfatal("ream: init log");
dropblk(b);
bh = b->bp.hash;
bo = b->bp.addr;
b = cachepluck();
memset(b->buf, 0, sizeof(b->buf));
b->type = Tarena;
b->bp.addr = start;
b->data = b->buf;
a->loghd.addr = bo;
a->loghd.hash = bh;
a->loghd.gen = -1;
a->size = asz;
a->used = Blksz;
a->logtl = nil;
packarena(b->data, Blksz, a, fi);
finalize(b);
if(syncblk(b) == -1)
sysfatal("ream: write arena: %r");
dropblk(b);
}
void
reamfs(char *dev)
{
Blk *sb, *mb, *ab, *ub;
vlong sz, asz, off;
Mount *mnt, *adm;
Arena *a;
Dir *d;
int i;
if((fs->fd = open(dev, ORDWR)) == -1)
sysfatal("open %s: %r", dev);
if((d = dirfstat(fs->fd)) == nil)
sysfatal("ream: %r");
sz = d->length;
free(d);
if(sz < 512*MiB)
sysfatal("ream: disk too small");
if((mnt = mallocz(sizeof(Mount), 1)) == nil)
sysfatal("ream: alloc mount: %r");
if((mnt->root = mallocz(sizeof(Tree), 1)) == nil)
sysfatal("ream: alloc tree: %r");
if((adm = mallocz(sizeof(Mount), 1)) == nil)
sysfatal("ream: alloc mount: %r");
if((adm->root = mallocz(sizeof(Tree), 1)) == nil)
sysfatal("ream: alloc tree: %r");
fs->narena = (sz + 64ULL*GiB - 1) / (64ULL*GiB);
if(fs->narena < 8)
fs->narena = 8;
if(fs->narena >= 128)
fs->narena = 128;
if((fs->arenas = calloc(fs->narena, sizeof(Arena))) == nil)
sysfatal("malloc: %r");
asz = sz/fs->narena;
asz = asz - (asz % Blksz) - Blksz;
fs->arenasz = asz;
off = 0;
for(i = 0; i < fs->narena; i++){
print("\tarena %d: %lld blocks at %llx\n", i, asz/Blksz, off);
initarena(&fs->arenas[i], fs, off, asz);
off += asz;
}
for(i = 0; i < fs->narena; i++){
a = &fs->arenas[i];
if((loadarena(a, fs, i*asz)) == -1)
sysfatal("ream: loadarena: %r");
if(loadlog(a, a->loghd) == -1)
sysfatal("load log: %r");
if(compresslog(a) == -1)
sysfatal("compress log: %r");
}
if((mb = newblk(mnt->root, Tleaf)) == nil)
sysfatal("ream: allocate root: %r");
holdblk(mb);
initroot(mb);
finalize(mb);
syncblk(mb);
mnt->root->ht = 1;
mnt->root->bp = mb->bp;
if((ab = newblk(adm->root, Tleaf)) == nil)
sysfatal("ream: allocate root: %r");
if((ub = newblk(adm->root, Tdat)) == nil)
sysfatal("ream: allocate root: %r");
holdblk(ab);
holdblk(ub);
if(reamuser != nil){
defaultusers = smprint(
"-1:adm::%s\n"
"0:none::\n"
"1:%s:%s:\n",
reamuser, reamuser, reamuser);
}
memcpy(ub->data, defaultusers, strlen(defaultusers));
finalize(ub);
syncblk(ub);
initadm(ab, ub, strlen(defaultusers));
finalize(ab);
syncblk(ab);
adm->root->ht = 1;
adm->root->bp = ab->bp;
/*
* Now that we have a completely empty fs, give it
* a single snap block that the tree will insert
* into, and take a snapshot as the initial state.
*/
if((sb = newblk(mnt->root, Tleaf)) == nil)
sysfatal("ream: allocate snaps: %r");
holdblk(sb);
initsnap(sb, mb, ab);
finalize(sb);
syncblk(sb);
fs->snap.bp = sb->bp;
fs->snap.ht = 1;
dropblk(mb);
dropblk(ab);
dropblk(ub);
dropblk(sb);
fs->nextqid = Nreamqid;
for(i = 0; i < fs->narena; i++){
a = &fs->arenas[i];
finalize(a->logtl);
if(syncblk(a->logtl) == -1)
sysfatal("sync arena: %r");
packarena(a->b->data, Blksz, a, fs);
finalize(a->b);
if(syncblk(a->b) == -1)
sysfatal("sync arena: %r");
}
free(mnt);
}
void
growfs(char *dev)
{
vlong sz, off;
int i, narena;
Arena *a;
Fshdr fi;
Dir *d;
if((fs->fd = open(dev, ORDWR)) == -1)
sysfatal("open %s: %r", dev);
if((d = dirfstat(fs->fd)) == nil)
sysfatal("ream: %r");
sz = d->length;
free(d);
if((fs->arenas = calloc(1, sizeof(Arena))) == nil)
sysfatal("malloc: %r");
fs->narena = 1;
for(i = 0; i < fs->narena; i++){
Arena *a;
a = &fs->arenas[i];
if((loadarena(a, &fi, i*fs->arenasz)) == -1)
sysfatal("growfs: %r");
if(fs->narena == 1){
fs->Fshdr = fi;
if((fs->arenas = realloc(fs->arenas, fs->narena*sizeof(Arena))) == nil)
sysfatal("malloc: %r");
}
}
narena = sz/fs->arenasz;
off = fs->arenasz * fs->narena;
if(narena <= fs->narena)
sysfatal("disk too small for more arenas");
if((fs->arenas = realloc(fs->arenas, narena*sizeof(Arena))) == nil)
sysfatal("malloc: %r");
for(i = fs->narena; i < narena; i++){
a = &fs->arenas[i];
print("\tadding %d: %lld blocks at %llx\n", i, fs->arenasz/Blksz, off);
initarena(&fs->arenas[i], fs, off, fs->arenasz);
if((loadarena(a, &fi, i*fs->arenasz)) == -1)
sysfatal("growfs: %r");
off += fs->arenasz;
}
fs->narena = narena;
for(i = 0; i < narena; i++){
a = &fs->arenas[i];
packarena(a->b->data, Blksz, a, fs);
finalize(a->b);
if(syncblk(a->b) == -1)
sysfatal("sync arena: %r");
}
}