shithub: gefs

ref: 7fa15946915dfffc3856c9075b20f591d1b00195
dir: /ream.c/

View raw version
#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");
	}
}