git: 9front

Download patch

ref: 875ae911d2e652816ff8fb91ab252dee9e342be8
parent: 8a309819457c3d0b1a248eac4d6effb1e989423d
author: Ori Bernstein <ori@eigenstate.org>
date: Wed Sep 24 09:27:54 EDT 2025

gefs: dump block state on assertion failures

with luck, this can lead to better bug reports.

--- a/sys/src/cmd/gefs/blk.c
+++ b/sys/src/cmd/gefs/blk.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 #include <fcall.h>
 #include <avl.h>
 
@@ -37,8 +38,8 @@
 void
 syncblk(Blk *b)
 {
-	assert(checkflag(b, Bfinal, 0));
-	assert(b->bp.addr >= 0);
+	bassert(b, checkflag(b, Bfinal, 0));
+	bassert(b, b->bp.addr >= 0);
 	tracex("syncblk", b->bp, b->type, -1);
 	if(pwrite(fs->fd, b->buf, Blksz, b->bp.addr) == -1)
 		broke("%B %s: %r", b->bp, Eio);
@@ -92,7 +93,7 @@
 		b->logsz = UNPACK16(p);		p += 2;
 		b->logh = UNPACK64(p);		p += 8;
 		b->logp = unpackbp(p, Ptrsz);	p += Ptrsz;
-		assert(p - b->buf == Loghdsz);
+		bassert(b, p - b->buf == Loghdsz);
 		b->data = p;
 		break;
 	case Tpivot:
@@ -100,13 +101,13 @@
 		b->valsz = UNPACK16(p);		p += 2;
 		b->nbuf = UNPACK16(p);		p += 2;
 		b->bufsz = UNPACK16(p);		p += 2;
-		assert(p - b->buf == Pivhdsz);
+		bassert(b, p - b->buf == Pivhdsz);
 		b->data = p;
 		break;
 	case Tleaf:
 		b->nval = UNPACK16(p);		p += 2;
 		b->valsz = UNPACK16(p);		p += 2;
-		assert(p - b->buf == Leafhdsz);
+		bassert(b, p - b->buf == Leafhdsz);
 		b->data = p;
 		break;
 	}
@@ -119,7 +120,7 @@
 	}
 	if((!flg&GBnochk) && ck != xh)
 		broke("%s: %ullx %llux != %llux", Ecorrupt, bp.addr, xh, ck);
-	assert(b->magic == Magic);
+	bassert(b, b->magic == Magic);
 }
 
 static Arena*
@@ -244,7 +245,7 @@
 	lb = a->logbuf[0];
 	if(lb == a->logtl)
 		lb = a->logbuf[1];
-	assert(agetl(&lb->ref) == 1);
+	bassert(lb, agetl(&lb->ref) == 1);
 	aswapl(&lb->flag, Bstatic);
 	initblk(lb, o, -1, Tlog);
 	traceb("logblk" , lb->bp);
@@ -276,9 +277,9 @@
 		assert(off < end);
 	}
 	lb = a->logtl;
-	assert(agetl(&lb->ref) > 0);
-	assert(lb->type == Tlog);
-	assert(lb->logsz >= 0);
+	bassert(lb, agetl(&lb->ref) > 0);
+	bassert(lb, lb->type == Tlog);
+	bassert(lb, lb->logsz >= 0);
 	dprint("logop %d: %llx+%llx@%x\n", op, off, len, lb->logsz);
 
 	if(checkflag(lb, 0, Bdirty))
@@ -341,7 +342,7 @@
 	traceb("loadlog", bp);
 	b = a->logbuf[0];
 	while(1){
-		assert(checkflag(b, Bstatic, Bcached));
+		bassert(b, checkflag(b, Bstatic, Bcached));
 		holdblk(b);
 		readblk(b, bp, 0);
 		dprint("\tload %B chain %B\n", bp, b->logp);
@@ -736,8 +737,8 @@
 		nexterror();
 	}
 	if((b = cacheget(bp.addr)) != nil){
-		assert(checkflag(b, 0, Bfreed));
-		assert(b->bp.gen == bp.gen);
+		bassert(b, checkflag(b, 0, Bfreed));
+		bassert(b, b->bp.gen == bp.gen);
 	} else {
 		b = cachepluck();
 		b->alloced = getcallerpc(&bp);
@@ -823,7 +824,7 @@
 	tracex("freeb", b->bp, getcallerpc(&t), -1);
 	setflag(b, Blimbo, 0);
 	holdblk(b);
-	assert(agetl(&b->ref) > 1);
+	bassert(b, agetl(&b->ref) > 1);
 	limbo(DFblk, b);
 }
 
@@ -966,8 +967,8 @@
 	Arena *a;
 	Qent qe;
 
-	assert(checkflag(b, Bdirty, Bqueued|Bstatic));
-	assert(b->bp.addr >= 0);
+	bassert(b, checkflag(b, Bdirty, Bqueued|Bstatic));
+	bassert(b, b->bp.addr >= 0);
 	finalize(b);
 	if(checkflag(b, 0, Bcached)){
 		cacheins(b);
@@ -1018,7 +1019,7 @@
 	else
 		abort();
 	if(qe.b != nil)
-		assert(agetl(&qe.b->ref) > 0);
+		bassert(qe.b, agetl(&qe.b->ref) > 0);
 	qlock(&q->lk);
 	qe.qgen = agetv(&fs->qgen);
 	while(q->nheap == q->heapsz)
--- a/sys/src/cmd/gefs/cache.c
+++ b/sys/src/cmd/gefs/cache.c
@@ -31,8 +31,8 @@
 	 * to put this into the LRU, because
 	 * its now in use.
 	 */
-	assert(b->magic == Magic);
-	assert(checkflag(b, 0, Bstatic));
+	bassert(b, b->magic == Magic);
+	bassert(b, checkflag(b, 0, Bstatic));
 	if(agetl(&b->ref) != 0){
 		qunlock(&fs->lrulk);
 		return;
@@ -58,8 +58,8 @@
 	 * to put this into the LRU, because
 	 * its now in use.
 	 */
-	assert(b->magic == Magic);
-	assert(checkflag(b, 0, Bstatic));
+	bassert(b, b->magic == Magic);
+	bassert(b, checkflag(b, 0, Bstatic));
 	if(agetl(&b->ref) != 0){
 		qunlock(&fs->lrulk);
 		return;
@@ -81,16 +81,16 @@
 	Bucket *bkt;
 	u32int h;
 
-	assert(b->magic == Magic);
+	bassert(b, b->magic == Magic);
 	h = ihash(b->bp.addr);
 	bkt = &fs->bcache[h % fs->cmax];
 	qlock(&fs->lrulk);
 	traceb("cache", b->bp);
-	assert(checkflag(b, 0, Bstatic|Bcached));
+	bassert(b, checkflag(b, 0, Bstatic|Bcached));
 	setflag(b, Bcached, 0);
-	assert(b->hnext == nil);
+	bassert(b, b->hnext == nil);
 	for(Blk *bb = bkt->b; bb != nil; bb = bb->hnext)
-		assert(b != bb && b->bp.addr != bb->bp.addr);
+		bassert(b, b != bb && b->bp.addr != bb->bp.addr);
 	b->cached = getcallerpc(&b);
 	b->hnext = bkt->b;
 	bkt->b = b;
@@ -115,7 +115,7 @@
 	for(b = bkt->b; b != nil; b = b->hnext){
 		if(b->bp.addr == addr){
 			/* FIXME: Until we clean up snap.c, we can have dirty blocks in cache */
-			assert(checkflag(b, Bcached, Bstatic)); //Bdirty));
+			bassert(b, checkflag(b, Bcached, Bstatic)); //Bdirty));
 			*p = b->hnext;
 			b->uncached = getcallerpc(&addr);
 			b->hnext = nil;
@@ -171,13 +171,13 @@
 		rsleep(&fs->lrurz);
 
 	b = fs->ctail;
-	assert(b->magic == Magic);
-	assert(agetl(&b->ref) == 0);
+	bassert(b, b->magic == Magic);
+	bassert(b, agetl(&b->ref) == 0);
 	if(checkflag(b, Bcached, 0))
 		cachedel_lk(b->bp.addr);
 	if(checkflag(b, Bcached, 0))
 		fprint(2, "%B cached %#p freed %#p\n", b->bp, b->cached, b->freed);
-	assert(checkflag(b, 0, Bcached));
+	bassert(b, checkflag(b, 0, Bcached));
 	lrudel(b);
 	aswapl(&b->flag, 0);
 	b->lasthold = 0;
--- a/sys/src/cmd/gefs/fns.h
+++ b/sys/src/cmd/gefs/fns.h
@@ -128,23 +128,19 @@
 void	showtreeroot(int, Tree*);
 int	checkfs(int);
 
+
 #define dprint(...) \
-	do{ \
-		if(debug) fprint(2, __VA_ARGS__); \
-	}while(0)
+		if(debug) fprint(2, __VA_ARGS__)
 
 #define fatal(...) \
-	do{ \
-		fprint(2, __VA_ARGS__); \
-		abort(); \
-	}while(0)
+	fprint(2, __VA_ARGS__), abort()
 
 #define tracex(msg, bp, v0, v1) \
-	do{ \
-		if(fs->trace != nil) \
-			_trace(msg, bp, v0, v1); \
-	} while(0)
+		if(fs->trace != nil) _trace(msg, bp, v0, v1)
 
+#define bassert(b, cond) \
+	if(cond){}else _babort(b->bp.addr, "cond")
+
 #define traceb(msg, bp)	tracex(msg, bp, -1, -1)
 #define tracev(msg, v0)	tracex(msg, Zb, v0, -1)
 #define tracem(msg)	tracex(msg, Zb, -1, -1)
@@ -153,10 +149,12 @@
 _Noreturn void	error(char*, ...);
 _Noreturn void	broke(char*, ...);
 _Noreturn void	nexterror(void);
+_Noreturn void	_babort(vlong, char*);
 #define waserror()	(setjmp(*_waserror()))
 #define errmsg()	((*errctx)->err)
 #define	poperror()	assert((*errctx)->nerrlab-- > 0)
 #define estacksz()	((*errctx)->nerrlab)
+void	writetrace(void*, vlong);
 void	_trace(char*, Bptr, vlong, vlong);
 char*	packstr(char*, char*, char*);
 
@@ -210,4 +208,4 @@
 void	runtasks(int, void*);
 void	runsync(int, void*);
 void	runsweep(int, void*);
-void	runsweep(int, void*);
+void	runsnap(int, void*);
--- a/sys/src/cmd/gefs/main.c
+++ b/sys/src/cmd/gefs/main.c
@@ -31,6 +31,43 @@
 Errctx	**errctx;
 
 void
+writetrace(void *bfd, vlong addr)
+{
+	Trace *t;
+	long ti;
+	int i;
+
+	ti = agetl(&fs->traceidx);
+	for(i = 0; i < fs->ntrace; i++){
+		t = &fs->trace[(ti+ i) % fs->ntrace];
+		if(t->msg[0] == 0)
+			continue;
+		if(t->bp.addr != -1 && t->bp.addr != addr)
+			continue;
+		Bprint(bfd, "[%d@%d] %s", t->tid, t->qgen, t->msg);
+		if(t->bp.addr != -1)
+			Bprint(bfd, " %B", t->bp);
+		if(t->v0 != -1)
+			Bprint(bfd, " %llx", t->v0);
+		if(t->v1 != -1)
+			Bprint(bfd, " %llx", t->v1);
+		Bprint(bfd, "\n");
+	}
+}
+
+_Noreturn void
+_babort(vlong addr, char *msg)
+{
+	Biobuf *bfd;
+
+	bfd = Bfdopen(2, OWRITE);
+	writetrace(bfd, addr);
+	Bprint(bfd, "assert failed for [%llx]: %s\n", addr, msg);
+	Bterm(bfd);
+	abort();
+}
+
+void
 _trace(char *msg, Bptr bp, vlong v0, vlong v1)
 {
 	Trace *t;
--- a/sys/src/cmd/gefs/tree.c
+++ b/sys/src/cmd/gefs/tree.c
@@ -104,7 +104,7 @@
 	char *p;
 	int o;
 
-	assert(i >= 0 && i < b->nval);
+	bassert(b, i >= 0 && i < b->nval);
 	p = b->data + 2*i;
 	o = UNPACK16(p);	p = b->data + o;
 	kv->nk = UNPACK16(p);	p += 2;
@@ -133,8 +133,8 @@
 	off = spc - b->valsz;
 
 	if(kv->k[0] == Kent) assert(kv->nv != 0);
-	assert(2*(b->nval+1) + b->valsz <= spc);
-	assert(2*(b->nval+1) <= off);
+	bassert(b, 2*(b->nval+1) + b->valsz <= spc);
+	bassert(b, 2*(b->nval+1) <= off);
 
 	p = b->data + 2*b->nval;
 	PACK16(p, off);
@@ -169,7 +169,7 @@
 	char *p;
 	int o;
 
-	assert(b->type == Tpivot);
+	bassert(b, b->type == Tpivot);
 	b->bufsz += msgsz(m)-2;
 
 	p = b->data + Pivspc + 2*b->nbuf;
@@ -192,8 +192,8 @@
 	char *p;
 	int o;
 
-	assert(b->type == Tpivot);
-	assert(i >= 0 && i < b->nbuf);
+	bassert(b, b->type == Tpivot);
+	bassert(b, i >= 0 && i < b->nbuf);
 	p = b->data + Pivspc + 2*i;
 	o = UNPACK16(p);
 	p = b->data + Pivspc + o;
@@ -284,7 +284,7 @@
 static int
 buffill(Blk *b)
 {
-	assert(b->type == Tpivot);
+	bassert(b, b->type == Tpivot);
 	return 2*b->nbuf + b->bufsz;
 }
 
@@ -291,7 +291,7 @@
 static int
 filledbuf(Blk *b, int nmsg, int needed)
 {
-	assert(b->type == Tpivot);
+	bassert(b, b->type == Tpivot);
 	return 2*(b->nbuf+nmsg) + b->bufsz + needed > Bufspc;
 }
 
@@ -298,7 +298,7 @@
 static int
 filledleaf(Blk *b, int needed)
 {
-	assert(b->type == Tleaf);
+	bassert(b, b->type == Tleaf);
 	return 2*(b->nval+1) + b->valsz + needed > Leafspc;
 }
 
@@ -310,7 +310,7 @@
 	 * at all times, so that splits along the whole path
 	 * have somewhere to go as they propagate up.
 	 */
-	assert(b->type == Tpivot);
+	bassert(b, b->type == Tpivot);
 	return 2*(b->nval+1) + b->valsz + reserve*Kpmax > Pivspc;
 }
 
@@ -435,7 +435,6 @@
 	default:
 		fatal("invalid op %d\n", m->op);
 	}
-	return 0;
 }
 
 static Blk*
@@ -707,7 +706,7 @@
 	if(halfsz > Leafspc/2)
 		halfsz = Leafspc/2;
 	spc = Leafspc - (halfsz + Msgmax);
-	assert(b->nval >= 4);
+	bassert(b, b->nval >= 4);
 	while(i < b->nval){
 		/*
 		 * We're trying to balance size,
@@ -815,7 +814,7 @@
 	d = l;
 	copied = 0;
 	halfsz = (2*b->nval + b->valsz)/2;
-	assert(b->nval >= 4);
+	bassert(b, b->nval >= 4);
 	for(i = 0; i < b->nval; i++){
 		/*
 		 * We're trying to balance size,
@@ -1000,7 +999,7 @@
 {
 	int na, nb, ma, mb, imbalance;
 
-	assert(a->type == b->type);
+	bassert(a, a->type == b->type);
 
 	na = 2*a->nval + a->valsz;
 	nb = 2*b->nval + b->valsz;
@@ -1327,8 +1326,8 @@
 	else
 		fatal("broken path change");
 
-	assert(rb->bp.addr != 0);
-	assert(rb->bp.addr != 0);
+	bassert(rb, rb->bp.addr != 0);
+	bassert(rb, rb->bp.addr != 0);
 
 	lock(&t->lk);
 	traceb("setroot", rb->bp);
--