shithub: gefs

Download patch

ref: ef7604325ba923d67906222b2130f76e067b7fbb
parent: 9b157a935a17079a2ca832ce95a2e29deeca1665
author: Ori Bernstein <[email protected]>
date: Tue Nov 21 21:36:10 EST 2023

tree: move to kernel-style error handling

--- a/blk.c
+++ b/blk.c
@@ -47,13 +47,14 @@
 	}
 }
 
-int
+void
 syncblk(Blk *b)
 {
 	assert(checkflag(b, Bfinal));
 	assert(b->bp.addr >= 0);
 	clrflag(b, Bdirty);
-	return pwrite(fs->fd, b->buf, Blksz, b->bp.addr);
+	if(pwrite(fs->fd, b->buf, Blksz, b->bp.addr) == -1)
+		broke("%r");
 }
 
 static Blk*
@@ -71,10 +72,8 @@
 	rem = Blksz;
 	while(rem != 0){
 		n = pread(fs->fd, b->buf, rem, off);
-		if(n <= 0){
-			dropblk(b);
-			return nil;
-		}
+		if(n <= 0)
+			error("%r");
 		off += n;
 		rem -= n;
 	}
@@ -98,8 +97,7 @@
 	b->type = (flg&GBraw) ? Tdat : UNPACK16(b->buf+0);
 	switch(b->type){
 	default:
-		fprint(2, "invalid block type %d @%llx\n", b->type, bp);
-		return nil;
+		broke("invalid block type %d @%llx\n", b->type, bp);
 		break;
 	case Tdat:
 	case Tsuper:
@@ -243,8 +241,7 @@
 		cachedel(lb->bp.addr);
 	initblk(lb, o, -1, Tlog);
 	finalize(lb);
-	if(syncblk(lb) == -1)
-		return nil;
+	syncblk(lb);
 	return lb;
 }
 
@@ -296,10 +293,7 @@
 		lb->logp = nl->bp;
 		setflag(lb, Bdirty);
 		finalize(lb);
-		if(syncblk(lb) == -1){
-			fs->broken = 1;
-			return -1;
-		}
+		syncblk(lb);
 		a->logtl = nl;
 		a->nlog++;
 		lb = nl;
@@ -508,10 +502,8 @@
 	r = (Arange*)t->root;
 	if(!force && a->size - a->used <= a->reserve)
 		return -1;
-	if(r == nil){
-		fprint(2, "out of space");
-		abort();
-	}
+	if(r == nil)
+		broke(Efull);
 
 	/*
 	 * A bit of sleight of hand here:
@@ -537,8 +529,6 @@
 	int r;
 
 	r = -1;
-assert(b >= a->hd->bp.addr + Blksz);
-assert(b < a->tl->bp.addr);
 	if(logappend(a, b, Blksz, LogFree) == -1)
 		return -1;
 	if(a->loghd.addr == -1)
@@ -593,8 +583,13 @@
 	tries++;
 	if(canqlock(a) == 0)
 		goto Again;
+	if(waserror()){
+		qunlock(a);
+		nexterror();
+	}
 	if((b = blkalloc_lk(a, 0)) == -1){
 		qunlock(a);
+		poperror();
 		goto Again;
 	}
 	if(logappend(a, b, Blksz, LogAlloc) == -1){
@@ -604,6 +599,7 @@
 	if(a->loghd.addr == -1)
 		a->loghd = a->logtl->bp;
 	qunlock(a);
+	poperror();
 	return b;
 }
 
@@ -613,11 +609,8 @@
 	Blk *ob;
 
 	ob = cacheget(bp);
-	if(ob != nil){
-		fprint(2, "dup block: %#p %B (azoced %#zx freed %#zx lasthold: %#zx, lastdrop: %#zx)\n",
-			ob, ob->bp, ob->alloced, ob->freed, ob->lasthold, ob->lastdrop);
-		abort();
-	}
+	if(ob != nil)
+		fatal("double alloc: %#p %B %#p %B", b, b->bp, ob, ob->bp);
 	b->type = ty;
 	b->bp.addr = bp;
 	b->bp.hash = -1;
@@ -748,11 +741,7 @@
 		qunlock(&fs->blklk[i]);
 		return b;
 	}
-	if((b = readblk(bp.addr, flg)) == nil){
-		fprint(2, "could not read %B\n", bp);
-		qunlock(&fs->blklk[i]);
-		return nil;
-	}
+	b = readblk(bp.addr, flg);
 	b->alloced = getcallerpc(&bp);
 	b->bp.hash = blkhash(b);
 	if((flg&GBnochk) == 0){
@@ -1084,11 +1073,7 @@
 			qunlock(&fs->synclk);
 		}else{
 			if(checkflag(qe.b, Bfreed) == 0)
-			if(syncblk(qe.b) == -1){
-				ainc(&fs->broken);
-				fprint(2, "write: %r\n");
-				abort();
-			}
+				syncblk(qe.b);
 			dropblk(qe.b);
 		}
 	}
@@ -1102,11 +1087,17 @@
 	Qent qe;
 	int i;
 
+	if(waserror()){
+		fprint(2, "failed to sync: %s\n", errmsg());
+		nexterror();
+	}
+
 	if(fs->rdonly)
 		return;
 	qlock(&fs->synclk);
 	if(!fs->snap.dirty){
 		qunlock(&fs->synclk);
+		poperror();
 		return;
 	}
 	flushdlcache(0);
@@ -1128,8 +1119,7 @@
 		qlock(a);
 		syncbarrier(a, gen);
 		finalize(a->logtl);
-		if(syncblk(a->logtl) == -1)
-			sysfatal("sync arena: %r");
+		syncblk(a->logtl);
 		qunlock(a);
 	}
 	/*
@@ -1142,8 +1132,7 @@
 		qlock(a);
 		packarena(a->hd->data, Blksz, a);
 		finalize(a->hd);
-		if(syncblk(a->hd) == -1)
-			sysfatal("sync arena: %r");
+		syncblk(a->hd);
 		qunlock(a);
 	}
 	/*
@@ -1159,10 +1148,8 @@
 	packsb(fs->sb1->buf, Blksz, fs);
 	finalize(fs->sb0);
 	finalize(fs->sb1);
-	if(syncblk(fs->sb0) == -1)
-		sysfatal("sync sb: %r");
-	if(syncblk(fs->sb1) == -1)
-		sysfatal("sync sb: %r");
+	syncblk(fs->sb0);
+	syncblk(fs->sb1);
 	fs->snap.dirty = 0;
 	/*
 	 * pass 3: sync block footers; if we crash here,
@@ -1174,8 +1161,7 @@
 		qlock(a);
 		packarena(a->tl->data, Blksz, a);
 		finalize(a->tl);
-		if(syncblk(a->tl) == -1)
-			sysfatal("sync arena: %r");
+		syncblk(a->tl);
 		qunlock(a);
 	}
 	/*
@@ -1190,4 +1176,5 @@
 	fs->snapdl.tl.gen = -1;
 	fs->snapdl.ins = nil;
 	qunlock(&fs->synclk);
+	poperror();
 }
--- a/dat.h
+++ b/dat.h
@@ -1,6 +1,7 @@
 typedef struct Blk	Blk;
 typedef struct Amsg	Amsg;
 typedef struct Gefs	Gefs;
+typedef struct Errctx	Errctx;
 typedef struct Fmsg	Fmsg;
 typedef struct Fid	Fid;
 typedef struct Msg	Msg;
@@ -79,7 +80,8 @@
 	Logspc		= Blksz - Loghdsz,
 	Logslop		= 16+16+8,			/* val, nextb, chain */
 	Leafspc 	= Blksz - Leafhdsz,
-	Msgmax  	= 1 + (Kvmax > Kpmax ? Kvmax : Kpmax)
+	Msgmax  	= 1 + (Kvmax > Kpmax ? Kvmax : Kpmax),
+	Estacksz	= 64,
 };
 
 enum {
@@ -358,6 +360,12 @@
 	Bptr	tl;	/* deadlist tail */
 };
 
+struct Errctx {
+	char	err[128];
+	jmp_buf	errlab[Estacksz];
+	int	nerrlab;
+};
+
 struct Arange {
 	Avl;
 	vlong	off;
@@ -523,7 +531,6 @@
 
 
 	int	fd;
-	long	broken;
 	long	rdonly;
 	int	noauth;
 
--- a/fns.h
+++ b/fns.h
@@ -11,6 +11,7 @@
 extern int	debug;
 extern int	permissive;
 extern char*	reamuser;
+extern void**	errctx;
 extern Blk*	blkbuf;
 
 #define	UNPACK8(p)	(((uchar*)(p))[0])
@@ -47,7 +48,7 @@
 void	qput(Syncq*, Qent);
 
 Arena*	getarena(vlong);
-int	syncblk(Blk*);
+void	syncblk(Blk*);
 void	enqueue(Blk*);
 void	epochstart(int);
 void	epochend(int);
@@ -137,6 +138,15 @@
 		fprint(2, __VA_ARGS__); \
 		abort(); \
 	}while(0)
+
+jmp_buf*	_waserror(void);
+_Noreturn void	errorv(char*, va_list);
+_Noreturn void	error(char*, ...);
+_Noreturn void	broke(char*, ...);
+_Noreturn void	nexterror(void);
+#define waserror()	(setjmp(*_waserror()))
+#define errmsg()	(((Errctx*)*errctx)->err)
+#define	poperror()	(((Errctx*)*errctx)->nerrlab--)
 
 char*	pack8(int*, char*, char*, uchar);
 char*	pack16(int*, char*, char*, ushort);
--- a/fs.c
+++ b/fs.c
@@ -2198,10 +2198,6 @@
 			rerror(m, Erdonly);
 			continue;
  		}
-		if(fs->broken){
-			rerror(m, Efs);
-			continue;
-		}
 
 		qlock(&fs->mutlk);
 		epochstart(id);
@@ -2350,11 +2346,8 @@
 			for(i = 0; i < fs->narena; i++){
 				for(bp = oldhd[i]; bp.addr != -1; bp = nb){
 					epochstart(id);
-					if((b = getblk(bp, 0)) == nil){
-						fprint(2, "could not load %B\n", bp);
-						fs->broken = 1;
-						break;
-					}
+					if((b = getblk(bp, 0)) == nil)
+						broke("reading %B: %s", bp, errmsg());
 					nb = b->logp;
 					freeblk(nil, b, b->bp);
 					dropblk(b);
@@ -2393,10 +2386,8 @@
 				PACK64(m.k+9, off);
 				m.v = nil;
 				m.nv = 0;
-				if((e = upsert(am->mnt, &m, 1)) != nil){
-					fprint(2, "sweep: %s\n", e);
-					fs->broken++;
-				}
+				if((e = upsert(am->mnt, &m, 1)) != nil)
+					broke("reading %B: %s", bp, e);
 				epochend(id);
 				qunlock(&fs->mutlk);
 				epochclean();
--- a/main.c
+++ b/main.c
@@ -21,7 +21,63 @@
 char	*dev;
 vlong	cachesz = 512*MiB;
 Blk	*blkbuf;
+void	**errctx;
 
+jmp_buf*
+_waserror(void)
+{
+	Errctx *c;
+
+	c = *errctx;
+	c->nerrlab++;
+if(c->nerrlab >= Estacksz)
+for(int i = 0; i < Estacksz; i++) print("%zx %zx\n", c->errlab[i][0], c->errlab[i][1]); 
+	assert(c->nerrlab > 0 && c->nerrlab < Estacksz);
+	return c->errlab + (c->nerrlab-1);
+}
+
+_Noreturn void
+errorv(char *fmt, va_list ap)
+{
+	Errctx *c;
+
+	c = *errctx;
+	vsnprint(c->err, sizeof(c->err), fmt, ap);
+	assert(c->nerrlab > 0 && c->nerrlab < Estacksz);
+	longjmp(c->errlab[--c->nerrlab], -1);
+}
+
+_Noreturn void
+broke(char *fmt, ...)
+{
+	va_list ap;
+
+	aincl(&fs->rdonly, 1);
+	va_start(ap, fmt);
+	vfprint(2, fmt, ap);
+	errorv(fmt, ap);
+}
+
+_Noreturn void
+error(char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	errorv(fmt, ap);
+}
+
+
+_Noreturn void
+nexterror(void)
+{
+	Errctx *c;
+
+	c = *errctx;
+	assert(c->nerrlab > 0 && c->nerrlab < Estacksz);
+	longjmp(c->errlab[--c->nerrlab], -1);
+}
+
 static void
 initfs(vlong cachesz)
 {
@@ -68,6 +124,8 @@
 		sysfatal("can't fork: %r");
 	if (pid == 0) {
 		id = aincl(&fs->nworker, 1);
+		if((*errctx = mallocz(sizeof(Errctx), 1)) == nil)
+			sysfatal("malloc: %r");
 		procsetname("%s.%ld", text, id);
 		(*f)(id, arg);
 		exits("child returned");
@@ -194,6 +252,9 @@
 
 	initfs(cachesz);
 	initshow();
+	errctx = privalloc();
+	if((*errctx = mallocz(sizeof(Errctx), 1)) == nil)
+		sysfatal("malloc: %r");
 	fmtinstall('H', encodefmt);
 	fmtinstall('B', Bconv);
 	fmtinstall('M', Mconv);
--- a/ream.c
+++ b/ream.c
@@ -213,8 +213,7 @@
 	PACK64(p, (uvlong)LogSync);	p += 8;	/* barrier */
 	b->logsz = p - b->data;
 	finalize(b);
-	if(syncblk(b) == -1)
-		sysfatal("ream: init log");
+	syncblk(b);
 	dropblk(b);
 
 	bh = b->bp.hash;
@@ -245,10 +244,8 @@
 	packarena(tl->data, Arenasz, a);
 	finalize(hd);
 	finalize(tl);
-	if(syncblk(hd) == -1)
-		sysfatal("ream: write arena: %r");
-	if(syncblk(tl) == -1)
-		sysfatal("ream: write arena: %r");
+	syncblk(hd);
+	syncblk(tl);
 	a->hd = hd;
 	a->tl = tl;
 }
@@ -263,6 +260,8 @@
 	Dir *d;
 	int i;
 
+	if(waserror())
+		sysfatal("ream %s: %s\n", dev, errmsg());
 	if((fs->fd = open(dev, ORDWR)) == -1)
 		sysfatal("open %s: %r", dev);
 	if((d = dirfstat(fs->fd)) == nil)
@@ -385,16 +384,13 @@
 	for(i = 0; i < fs->narena; i++){
 		a = &fs->arenas[i];
 		finalize(a->logtl);
-		if(syncblk(a->logtl) == -1)
-			sysfatal("sync arena: %r");
+		syncblk(a->logtl);
 		packarena(a->hd->data, Blksz, a);
 		finalize(a->hd);
-		if(syncblk(a->hd) == -1)
-			sysfatal("sync arena: %r");
+		syncblk(a->hd);
 		packarena(a->tl->data, Blksz, a);
 		finalize(a->tl);
-		if(syncblk(a->tl) == -1)
-			sysfatal("sync arena: %r");
+		syncblk(a->tl);
 		fs->arenabp[i] = a->hd->bp;
 		dropblk(a->hd);
 		dropblk(a->tl);
@@ -413,14 +409,12 @@
 	packsb(sb1->buf, Blksz, fs);
 	finalize(sb0);
 	finalize(sb1);
-	if(syncblk(sb0) == -1)
-		sysfatal("sync superblock: %r");
-	if(syncblk(sb1) == -1)
-		sysfatal("sync superblock: %r");
+	syncblk(sb0);
+	syncblk(sb1);
 	dropblk(sb0);
 	dropblk(sb1);
-
 	free(mnt);
+	poperror();
 }
 
 void
@@ -432,6 +426,8 @@
 	Arena *a;
 	Dir *d;
 
+	if(waserror())
+		sysfatal("grow %s: %s\n", dev, errmsg());
 	if((fs->fd = open(dev, ORDWR)) == -1)
 		sysfatal("open %s: %r", dev);
 	if((d = dirfstat(fs->fd)) == nil)
@@ -475,17 +471,14 @@
 		packarena(a->tl->data, Blksz, a);
 		finalize(a->hd);
 		finalize(a->tl);
-		if(syncblk(a->hd) == -1)
-			sysfatal("sync arena: %r");
-		if(syncblk(a->tl) == -1)
-			sysfatal("sync arena: %r");
+		syncblk(a->hd);
+		syncblk(a->tl);
 	}
 	packsb(fs->sb0->buf, Blksz, fs);
 	packsb(fs->sb1->buf, Blksz, fs);
 	finalize(fs->sb0);
 	finalize(fs->sb1);
-	if(syncblk(fs->sb0) == -1)
-		sysfatal("sync superblock: %r");
-	if(syncblk(fs->sb1) == -1)
-		sysfatal("sync superblock: %r");
+	syncblk(fs->sb0);
+	syncblk(fs->sb1);
+	poperror();
 }
--- a/tree.c
+++ b/tree.c
@@ -27,6 +27,11 @@
 	int	pullsz;	/* size of pulled messages */
 };
 
+#define efreeblk(t, b) do { \
+	if(b != nil) \
+		freeblk(t, b, b->bp); \
+	} while(0)
+
 static void
 stablesort(Msg *m, int nm)
 {
@@ -454,7 +459,7 @@
  *
  * When pidx != -1, 
  */
-static int
+static void
 updateleaf(Tree *t, Path *up, Path *p)
 {
 	char buf[Msgmax];
@@ -477,8 +482,7 @@
 	 */
 	full = 0;
 	spc = Leafspc - blkfill(b);
-	if((n = newblk(t, b->type)) == nil)
-		return -1;
+	n = newblk(t, b->type);
 	assert(i >= 0 && j >= 0);
 	while(i < b->nval){
 		ok = 1;
@@ -550,7 +554,6 @@
 	}
 	p->npull = (j - up->lo);
 	p->nl = n;
-	return 0;
 }
 
 /*
@@ -561,7 +564,7 @@
  *
  * When pidx != -1, 
  */
-static int
+static void
 updatepiv(Tree *t, Path *up, Path *p, Path *pp)
 {
 	char buf[Msgmax];
@@ -570,8 +573,7 @@
 	Msg m, u;
 
 	b = p->b;
-	if((n = newblk(t, b->type)) == nil)
-		return -1;
+	n = newblk(t, b->type);
 	for(i = 0; i < b->nval; i++){
 		if(pp != nil && i == p->midx){
 			copyup(n, pp, nil);
@@ -624,7 +626,6 @@
 	}
 	p->npull = (j - up->lo);
 	p->nl = n;
-	return 0;
 }
 
 /*
@@ -632,7 +633,7 @@
  * would be inserted into. Split must never
  * grow the total height of the tree by more than 1.
  */
-static int
+static void
 splitleaf(Tree *t, Path *up, Path *p, Kvp *mid)
 {
 	char buf[Msgmax];
@@ -648,13 +649,15 @@
 	 * so we want to make a new block.
 	 */
 	b = p->b;
+	l = nil;
+	r = nil;
+	if(waserror()){
+		efreeblk(t, l);
+		efreeblk(t, r);
+		return;
+	}
 	l = newblk(t, b->type);
 	r = newblk(t, b->type);
-	if(l == nil || r == nil){
-		freeblk(t, l, l->bp);
-		freeblk(t, r, r->bp);
-		return -1;
-	}
 
 	d = l;
 	i = 0;
@@ -721,8 +724,7 @@
 	p->op = POsplit;
 	p->nl = l;
 	p->nr = r;
-
-	return 0;
+	poperror();
 }
 
 /*
@@ -731,7 +733,7 @@
  * grow the total height of the tree by more
  * than one.
  */
-static int
+static void
 splitpiv(Tree *t, Path *, Path *p, Path *pp, Kvp *mid)
 {
 	int i, copied, halfsz;
@@ -745,13 +747,15 @@
 	 * so we want to make a new bp->lock.
 	 */
 	b = p->b;
+	l = nil;
+	r = nil;
+	if(waserror()){
+		efreeblk(t, l);
+		efreeblk(t, r);
+		return;
+	}
 	l = newblk(t, b->type);
 	r = newblk(t, b->type);
-	if(l == nil || r == nil){
-		freeblk(t, l, l->bp);
-		freeblk(t, r, r->bp);
-		return -1;
-	}
 	d = l;
 	copied = 0;
 	halfsz = (2*b->nval + b->valsz)/2;
@@ -790,11 +794,9 @@
 	p->op = POsplit;
 	p->nl = l;
 	p->nr = r;
-
-	return 0;
 }
 
-static int
+static void
 merge(Tree *t, Path *p, Path *pp, int idx, Blk *a, Blk *b)
 {
 	Blk *d;
@@ -801,8 +803,7 @@
 	Msg m;
 	int i;
 
-	if((d = newblk(t, a->type)) == nil)
-		return -1;
+	d = newblk(t, a->type);
 	for(i = 0; i < a->nval; i++){
 		getval(a, i, &m);
 		setval(d, &m);
@@ -826,7 +827,6 @@
 	pp->nl = d;
 	pp->op = POmerge;
 	pp->nr = nil;
-	return 0;
 }
 
 /*
@@ -873,7 +873,7 @@
 	return 0;
 }
 
-static int
+static void
 rotate(Tree *t, Path *p, Path *pp, int midx, Blk *a, Blk *b, int halfpiv)
 {
 	int i, o, cp, sp, idx;
@@ -880,13 +880,15 @@
 	Blk *d, *l, *r;
 	Msg m;
 
+	l = nil;
+	r = nil;
+	if(waserror()){
+		efreeblk(t, l);
+		efreeblk(t, r);
+		return;
+	}
 	l = newblk(t, a->type);
 	r = newblk(t, a->type);
-	if(l == nil || r == nil){
-		freeblk(t, l, l->bp);
-		freeblk(t, r, r->bp);
-		return -1;
-	}
 	d = l;
 	cp = 0;
 	sp = -1;
@@ -937,10 +939,10 @@
 	pp->op = POrot;
 	pp->nl = l;
 	pp->nr = r;
-	return 0;
+	poperror();
 }
 
-static int
+static void
 rotmerge(Tree *t, Path *p, Path *pp, int idx, Blk *a, Blk *b)
 {
 	int na, nb, ma, mb, imbalance;
@@ -961,39 +963,40 @@
 		imbalance *= -1;
 	/* works for leaf, because 0 always < Bufspc */
 	if(na + nb < (Pivspc - 4*Msgmax) && ma + mb < Bufspc)
-		return merge(t, p, pp, idx, a, b);
+		merge(t, p, pp, idx, a, b);
 	else if(imbalance > 4*Msgmax)
-		return rotate(t, p, pp, idx, a, b, (na + nb)/2);
-	else
-		return 0;
+		rotate(t, p, pp, idx, a, b, (na + nb)/2);
 }
 
-static int
+static void
 trybalance(Tree *t, Path *p, Path *pp, int idx)
 {
 	Blk *l, *m, *r;
 	Kvp kl, kr;
-	int spc, ret, fill;
+	int spc, fill;
 	Bptr bp;
 
-	l = nil;
-	r = nil;
-	ret = -1;
 	if(p->idx == -1 || pp == nil || pp->nl == nil)
-		return 0;
+		return;
 	if(pp->op != POmod || pp->op != POmerge)
-		return 0;
+		return;
 
+	l = nil;
+	r = nil;
 	m = holdblk(pp->nl);
+	if(waserror()){
+		dropblk(m);
+		dropblk(l);
+		dropblk(r);
+		nexterror();
+	}
 	spc = (m->type == Tleaf) ? Leafspc : Pivspc;
 	if(idx-1 >= 0){
 		getval(p->b, idx-1, &kl);
 		bp = getptr(&kl, &fill);
 		if(fill + blkfill(m) < spc){
-			if((l = getblk(bp, 0)) == nil)
-				goto Out;
-			if(rotmerge(t, p, pp, idx-1, l, m) == -1)
-				goto Out;
+			l = getblk(bp, 0);
+			rotmerge(t, p, pp, idx-1, l, m);
 			goto Done;
 		}
 	}
@@ -1001,20 +1004,16 @@
 		getval(p->b, idx+1, &kr);
 		bp = getptr(&kr, &fill);
 		if(fill + blkfill(m) < spc){
-			if((r = getblk(bp, 0)) == nil)
-				goto Out;
-			if(rotmerge(t, p, pp, idx, m, r) == -1)
-				goto Out;
+			r = getblk(bp, 0);
+			rotmerge(t, p, pp, idx, m, r);
 			goto Done;
 		}
 	}
 Done:
-	ret = 0;
-Out:
 	dropblk(m);
 	dropblk(l);
 	dropblk(r);
-	return ret;
+	poperror();
 }
 
 static Path*
@@ -1037,14 +1036,12 @@
 	up = &path[npath - 2];
 	if(p->b->type == Tleaf){
 		if(!filledleaf(p->b, up->sz)){
-			if(updateleaf(t, p-1, p) == -1)
-				goto Error;
+			updateleaf(t, p-1, p);
 			enqueue(p->nl);
 			rp = p;
 		}else{
 
-			if(splitleaf(t, up, p, &mid) == -1)
-				goto Error;
+			splitleaf(t, up, p, &mid);
 			enqueue(p->nl);
 			enqueue(p->nr);
 		}
@@ -1055,20 +1052,17 @@
 	}
 	while(p != path){
 		if(!filledpiv(p->b, 1)){
-			if(trybalance(t, p, pp, p->idx) == -1)
-				goto Error;
+			trybalance(t, p, pp, p->idx);
 			/* If we merged the root node, break out. */
 			if(up == path && pp != nil && pp->op == POmerge && p->b->nval == 2){
 				rp = pp;
 				goto Out;
 			}
-			if(updatepiv(t, up, p, pp) == -1)
-				goto Error;
+			updatepiv(t, up, p, pp);
 			enqueue(p->nl);
 			rp = p;
 		}else{
-			if(splitpiv(t, up, p, pp, &mid) == -1)
-				goto Error;
+			splitpiv(t, up, p, pp, &mid);
 			enqueue(p->nl);
 			enqueue(p->nr);
 		}
@@ -1079,8 +1073,6 @@
 	if(pp->nl != nil && pp->nr != nil){
 		rp = &path[0];
 		rp->nl = newblk(t, Tpivot);
-		if(rp->nl == nil)
-			goto Error;
 		rp->npull = pp->npull;
 		rp->pullsz = pp->pullsz;
 		copyup(rp->nl, pp, nil);
@@ -1088,8 +1080,6 @@
 	}
 Out:
 	return rp;
-Error:
-	return nil;
 }
 
 static void
@@ -1154,7 +1144,7 @@
 	}
 }
 
-static char*
+static void
 fastupsert(Tree *t, Blk *b, Msg *msg, int nmsg)
 {
 	int i, c, o, ri, lo, hi, mid, nbuf;
@@ -1163,7 +1153,7 @@
 	Blk *r;
 
 	if((r = dupblk(t, b)) == nil)
-		return Enomem;
+		error(Enomem);
 	
 	nbuf = r->nbuf;
 	for(i = 0; i < nmsg; i++)
@@ -1208,7 +1198,6 @@
 	freeblk(t, b, b->bp);
 	dropblk(b);
 	dropblk(r);
-	return nil;
 }
 	
 
@@ -1226,12 +1215,20 @@
 	for(i = 0; i < nmsg; i++)
 		sz += msgsz(&msg[i]);
 	npull = 0;
+	path = nil;
+	npath = 0;
+	if(waserror()){
+		freepath(t, path, npath);
+		return errmsg();
+	}
 
 Again:
-	if((b = getroot(t, &height)) == nil)
-		return Efs;
-	if(b->type == Tpivot && !filledbuf(b, nmsg, sz))
-		return fastupsert(t, b, msg, nmsg);
+	b = getroot(t, &height);
+	if(b->type == Tpivot && !filledbuf(b, nmsg, sz)){
+		fastupsert(t, b, msg, nmsg);
+		poperror();
+		return nil;
+	}
 
 	/*
 	 * The tree can grow in height by 1 when we
@@ -1257,8 +1254,6 @@
 		getval(b, path[npath].idx, &sep);
 		bp = unpackbp(sep.v, sep.nv);
 		b = getblk(bp, 0);
-		if(b == nil)
-			goto Error;
 		npath++;
 	}
 	path[npath].b = b;
@@ -1272,8 +1267,6 @@
 
 	dh = -1;
 	rp = flush(t, path, npath);
-	if(rp == nil)
-		goto Error;
 	rb = rp->nl;
 
 	if(path[0].nl != nil)
@@ -1298,10 +1291,8 @@
 	freepath(t, path, npath);
 	if(npull != nmsg)
 		goto Again;
-	return 0;
-Error:
-	freepath(t, path, npath);
-	return Efs;
+	poperror();
+	return nil;
 }
 
 Blk*