shithub: gefs

ref: 130b071161bee5dbb1a03e4a5bd01ce72fc5804a
dir: /dump.c/

View raw version
#include <u.h>
#include <libc.h>
#include <avl.h>
#include <fcall.h>
#include <ctype.h>

#include "dat.h"
#include "fns.h"

char	spc[128];

static int
showkey(Fmt *fmt, Key *k)
{
	int n;

	/*
	 * dent: pqid[8] qid[8] -- a directory entry key.
	 * ptr:  off[8] hash[8] -- a key for an Dir block.
	 * dir:  fixed statbuf header, user ids
	 */
	if(k->nk == 0)
		return fmtprint(fmt, "\"\"");
	switch(k->k[0]){
	case Kdat:	/* qid[8] off[8] => ptr[16]:	pointer to data page */
		n = fmtprint(fmt, "dat qid:%llx off:%llx", UNPACK64(k->k+1), UNPACK64(k->k+9));
		break;
	case Kent:	/* pqid[8] name[n] => dir[n]:	serialized Dir */
		n = fmtprint(fmt, "ent dir:%llx, name:\"%.*s\"", UNPACK64(k->k+1), k->nk-11, k->k+11);
		break;
	case Klabel:	/* name[n] => tree[24]:	snapshot ref */
		n = fmtprint(fmt, "label name:\"%.*s\"", k->nk-1, k->k+1);
		break;
	case Ksnap:	/* name[n] => tree[24]:	snapshot root */
		n = fmtprint(fmt, "snap id:%lld", UNPACK64(k->k+1));
		break;
	case Ksuper:	/* qid[8] => pqid[8]:		parent dir */
		n = fmtprint(fmt, "up dir:%llx", UNPACK64(k->k+1));
		break;
	case Kslink:
		n = fmtprint(fmt, "slink gen:%llx, succ:%llx", UNPACK64(k->k+1), UNPACK64(k->k+9));
		break;
	case Kdlist:
		n = fmtprint(fmt, "dlist gen:%llx, bgen:%llx", UNPACK64(k->k+1), UNPACK64(k->k+9));
		break;
	default:
		n = fmtprint(fmt, "??? %.*H", k->nk, k->k);
		break;
	}
	return n;
}

static int
showval(Fmt *fmt, Kvp *v, int op, int flg)
{
	int n, ws;
	char *p;
	Tree t;
	Xdir d;

	n = 0;
	if(flg){
		assert(v->nv == Ptrsz+2);
		n = fmtprint(fmt, "(%B,%d)", unpackbp(v->v, v->nv), UNPACK16(v->v+Ptrsz));
		return n;
	}
	if(op == Odelete || op == Oclearb){
		n = fmtprint(fmt, "delete");
		return n;
	}
	switch(v->k[0]){
	case Kdat:	/* qid[8] off[8] => ptr[16]:	pointer to data page */
		switch(op){
		case Odelete:
		case Oclearb:
			n = 0;
			break;
		case Onop:
		case Oinsert:
			n = fmtprint(fmt, "ptr:%B", unpackbp(v->v, v->nv));
			break;
		}
		break;
	case Kent:	/* pqid[8] name[n] => dir[n]:	serialized Dir */
		switch(op){
		case Onop:
		case Oinsert:
			if(kv2dir(v, &d) == -1)
				n = fmtprint(fmt, "bad dir");
			else
				n = fmtprint(fmt, "[qid=(%llux,%lud,%d), %luo, t=%lld,%lld, l=%lld]",
					d.qid.path, d.qid.vers, d.qid.type,
					d.mode, d.atime, d.mtime, d.length);
			break;
		case Odelete:
			n = fmtprint(fmt, "delete");
			break;
		case Owstat:
			p = v->v;
			ws = *p++;
			if(ws & Owsize){
				n += fmtprint(fmt, "size:%llx ", UNPACK64(p));
				p += 8;
			}
			if(ws & Owmode){
				n += fmtprint(fmt, "mode:%uo ", UNPACK32(p));
				p += 4;
			}
			if(ws & Owmtime){
				n += fmtprint(fmt, "mtime:%llx ", UNPACK64(p));
				p += 8;
			}
			if(ws & Owatime){
				n += fmtprint(fmt, "mtime:%llx ", UNPACK64(p));
				p += 8;
			}
			if(ws & Owuid){
				n += fmtprint(fmt, "uid:%d ", UNPACK32(p));
				p += 4;
			}
			if(ws & Owgid){
				n += fmtprint(fmt, "gid:%d ", UNPACK32(p));
				p += 4;
			}
			if(ws & Owmuid){
				n += fmtprint(fmt, "muid:%d ", UNPACK32(p));
				p += 4;
			}
			if(p != v->v + v->nv){
				fprint(2, "v->nv: %d, sz=%d\n", v->nv, (int)(p - v->v));
				abort();
			}
			break;
		}
		break;
	case Ksnap:	/* name[n] => dent[16] ptr[16]:	snapshot root */
		if(unpacktree(&t, v->v, v->nv) == nil)
			n = fmtprint(fmt, "corrupt tree");
		else
			n = fmtprint(fmt, "<tree>");
		break;
	case Klabel:
		n = fmtprint(fmt, "snap id:\"%lld\"", UNPACK64(v->v+1));
		break;
	case Ksuper:	/* qid[8] => pqid[8]:		parent dir */
		n = fmtprint(fmt, "super dir:%llx, name:\"%.*s\")", UNPACK64(v->v+1), v->nv-11, v->v+11);
		break;
	case Kslink:
		n = fmtprint(fmt, "()");
		break;
	case Kdlist:
		n = fmtprint(fmt, "hd:%B, tl:%B", unpackbp(v->v, v->nv), unpackbp(v->v+Ptrsz, v->nv-Ptrsz));
		break;
	default:
		n = fmtprint(fmt, "??? %.*H", v->nk, v->k);
		break;
	}
	return n;

}

int
Bconv(Fmt *fmt)
{
	Bptr bp;

	bp = va_arg(fmt->args, Bptr);
	return fmtprint(fmt, "(%llx,%.16llux,%llx)", bp.addr, bp.hash, bp.gen);
}

int
Mconv(Fmt *fmt)
{
	char *opname[Nmsgtype] = {
	[Oinsert]	"Oinsert",
	[Odelete]	"Odelete",
	[Oclearb]	"Oclearb",
	[Owstat]	"Owstat",
	};
	Msg *m;
	int f, n;

	f = (fmt->flags & FmtSharp) != 0;
	m = va_arg(fmt->args, Msg*);
	if(m == nil)
		return fmtprint(fmt, "Msg{nil}");
	n = fmtprint(fmt, "Msg(%s, ", opname[m->op]);
	n += showkey(fmt, m);
	n += fmtprint(fmt, ") => (");
	n += showval(fmt, m, m->op, f);
	n += fmtprint(fmt, ")");
	return n;
}

int
Pconv(Fmt *fmt)
{
	Kvp *kv;
	int f, n;

	f = (fmt->flags & FmtSharp) != 0;
	kv = va_arg(fmt->args, Kvp*);
	if(kv == nil)
		return fmtprint(fmt, "Kvp{nil}");
	n = fmtprint(fmt, "Kvp(");
	n += showkey(fmt, kv);
	n += fmtprint(fmt, ") => (");
	n += showval(fmt, kv, Onop, f);
	n += fmtprint(fmt, ")");
	return n;
}

int
Kconv(Fmt *fmt)
{
	Key *k;
	int n;

	k = va_arg(fmt->args, Key*);
	if(k == nil)
		return fmtprint(fmt, "Key{nil}");
	n = fmtprint(fmt, "Key(");
	n += showkey(fmt, k);
	n += fmtprint(fmt, ")");
	return n;
}

int
Rconv(Fmt *fmt)
{
	Arange *r;

	r = va_arg(fmt->args, Arange*);
	if(r == nil)
		return fmtprint(fmt, "<Arange:nil>");
	else
		return fmtprint(fmt, "Arange(%lld+%lld)", r->off, r->len);
}

int
Qconv(Fmt *fmt)
{
	Qid q;

	q = va_arg(fmt->args, Qid);
	return fmtprint(fmt, "(%llx %ld %d)", q.path, q.vers, q.type);
}

static void
rshowblk(int fd, Blk *b, int indent, int recurse)
{
	Blk *c;
	int i;
	Bptr bp;
	Kvp kv;
	Msg m;

	if(indent > sizeof(spc)/4)
		indent = sizeof(spc)/4;
	if(b == nil){
		fprint(fd, "NIL\n");
		return;
	}
	fprint(fd, "%.*s[BLK]|{%B}\n", 4*indent, spc, b->bp);
	switch(b->type){
	case Tpivot:
		for(i = 0; i < b->nbuf; i++){
			getmsg(b, i, &m);
			fprint(fd, "%.*s[%03d]|%M\n", 4*indent, spc, i, &m);
		}
		/* wet floor */
	case Tleaf:
		for(i = 0; i < b->nval; i++){
			getval(b, i, &kv);
			if(b->type == Tpivot){
				fprint(fd, "%.*s[%03d]|%#P\n", 4*indent, spc, i, &kv);
				bp = unpackbp(kv.v, kv.nv);
				if((c = getblk(bp, 0)) == nil)
					sysfatal("failed load: %r");
				if(recurse)
					rshowblk(fd, c, indent + 1, 1);
				dropblk(c);
			}else{
				fprint(fd, "%.*s[%03d]|%P\n", 4*indent, spc, i, &kv);
			}
		}
		break;
	case Tmagic:
		fprint(fd, "magic\n");
		break;
	case Tarena:
		fprint(fd, "arena -- ");
		goto Show;
	case Tlog:
		fprint(fd, "log -- ");
		goto Show;
	case Tdlist:
		fprint(fd, "dlist -- ");
		goto Show;
	case Tdat:
		fprint(fd, "dat -- ");
	Show:
		for(i = 0; i < 32; i++){
			fprint(fd, "%x", b->buf[i] & 0xff);
			if(i % 4 == 3)
				fprint(fd, " ");
		}
		fprint(fd, "\n");
		break;
	}
}

void
showblk(int fd, Blk *b, char *m, int recurse)
{
	fprint(fd, "=== %s\n", m);
	rshowblk(fd, b, 0, recurse);
}

void
showtree(int fd, char **ap, int na)
{
	char *name;
	Tree *t;
	Blk *b;
	int h;

	name = "main";
	memset(&t, 0, sizeof(t));
	if(na == 1)
		name = ap[0];
	if(strcmp(name, "snap") == 0)
		t = &fs->snap;
	else if((t = opensnap(name)) == nil){
		fprint(fd, "open %s: %r\n", name);
		return;
	}
	b = getroot(t, &h);
	fprint(fd, "=== [%s] %B @%d\n", name, t->bp, t->ht);
	rshowblk(fd, b, 0, 1);
	dropblk(b);
	if(t != &fs->snap)
		closesnap(t);
}

void
showbp(int fd, Bptr bp, int recurse)
{
	Blk *b;

	b = getblk(bp, GBnochk);
	rshowblk(fd, b, 0, recurse);
	dropblk(b);
}

static void
showdeadbp(Bptr bp, void *p)
{
	fprint(*(int*)p, "\t\t\t%B\n", bp);
}

void
showtreeroot(int fd, Tree *t)
{
	fprint(fd, "\tgen:\t%lld\n", t->gen);
	fprint(fd, "\tprev:\t%lld\n", t->prev);
	fprint(fd, "\tnsucc:\t%d\n", t->nsucc);
	fprint(fd, "\tnlbl:\t%d\n", t->nlbl);
	fprint(fd, "\tht:\t%d\n", t->ht);
	fprint(fd, "\tbp:\t%B\n", t->bp);
}

void
showsnap(int fd, char **ap, int na)
{
	char *e, pfx[Snapsz];
	Mount *mnt;
	vlong id;
	Scan s;
	int sz;
	Tree t;

	/* dump the labels */
	if(na == 0){
		lock(&fs->mountlk);
		fprint(fd, "open:");
		for(mnt = fs->mounts; mnt != nil; mnt = mnt->next)
			fprint(fd, " %s\n", mnt->name);
		fprint(fd, "\n");
		unlock(&fs->mountlk);

		pfx[0] = Klabel;
		sz = 1;
		btnewscan(&s, pfx, sz);
		if((e = btenter(&fs->snap, &s)) != nil){
			fprint(fd, "scan: %s\n", e);
			btexit(&fs->snap, &s);
			return;
		}
		while(1){
			if((e = btnext(&fs->snap, &s, &s.kv)) != nil){
				fprint(fd, "scan: %s\n", e);
				break;
			}
			if(s.done)
				break;
			fprint(fd, "label: %P\n", &s.kv);
		}
		btexit(&fs->snap, &s);
	}

	/* dump the snapshots */
	pfx[0] = Ksnap;
	sz = 1;
	if(na != 0){
		sz = Snapsz;
		id = atoll(ap[0]);
		PACK64(pfx+1, id);
	}
	btnewscan(&s, pfx, sz);
	if((e = btenter(&fs->snap, &s)) != nil){
		fprint(fd, "scan: %s\n", e);
		btexit(&fs->snap, &s);
		return;
	}
	while(1){
		if((e = btnext(&fs->snap, &s, &s.kv)) != nil){
			fprint(fd, "scan: %s\n", e);
			break;
		}
		if(s.done)
			break;
		fprint(fd, "snap: %P\n", &s.kv);
		if(unpacktree(&t, s.kv.v, s.kv.nv) == nil){
			fprint(fd, "unpack: garbled tree\n");
			break;
		}
		showtreeroot(fd, &t);
	}
	btexit(&fs->snap, &s);
}

void
showdlist(int fd, char** ap, int na)
{
	char *p, *e, *err, pfx[Kvmax];
	Dlist dl;
	Bptr hd;
	Scan s;
	Blk *b;
	vlong id;
	int sz;

	pfx[0] = Kdlist;
	sz = 1;
	if(na != 0){
		sz = 9;
		id = atoll(ap[0]);
		PACK64(pfx+1, id);
	}
	btnewscan(&s, pfx, sz);
	if((err = btenter(&fs->snap, &s)) != nil){
		fprint(fd, "scan: %s\n", err);
		btexit(&fs->snap, &s);
		return;
	}
	while(1){
		if((e = btnext(&fs->snap, &s, &s.kv)) != nil){
			fprint(fd, "scan: %s\n", e);
			break;
		}
		if(s.done)
			break;
		fprint(fd, "dlist: %P\n", &s.kv);
		kv2dlist(&s.kv, &dl);
		hd = dl.hd;
		while(hd.addr != -1){
			if((b = getblk(hd, 0)) == nil){
				fprint(fd, "broken: %B\n", hd);
				break;
			}
			fprint(fd, "deadsz: %xm deadp=%B\n", b->deadsz, b->deadp);
			e = b->data + b->deadsz;
			for(p = b->data; p != e; p += 8)
				fprint(fd, "\tdead: %llx\n", UNPACK64(p));
			hd = b->deadp;
		}
	}
	btexit(&fs->snap, &s);
}

void
showcache(int fd, char**, int)
{
	Bucket *bkt;
	Blk *b;
	int i;

	for(i = 0; i < fs->cmax; i++){
		bkt = &fs->bcache[i];
		lock(bkt);
		if(bkt->b != nil)
			fprint(fd, "bkt%d\n", i);
		for(b = bkt->b; b != nil; b = b->hnext)
			if(b->ref != 1)
				fprint(fd, "\t%p[ref=%ld, t=%d] => %B\n", b, b->ref, b->type, b->bp);
		unlock(bkt);
	}
}

void
showfree(int fd, char **, int)
{
	Arange *r;
	int i;

	for(i = 0; i < fs->narena; i++){
		fprint(fd, "arena %d:\n", i);
		for(r = (Arange*)avlmin(fs->arenas[i].free); r != nil; r = (Arange*)avlnext(r))
			fprint(fd, "\t%llx+%llx\n", r->off, r->len);
	}
}

void
initshow(void)
{
	int i;

	memset(spc, ' ', sizeof(spc));
	for(i = 0; i < sizeof(spc); i += 4)
		spc[i] = '|';
}