shithub: gefs

Download patch

ref: 95332069fecfe2e7497b21dad8c06f1b93cb1d40
parent: 97700c98f4d56d8fafff628fb9356bab8cb1b5f3
author: Ori Bernstein <ori@eigenstate.org>
date: Wed Nov 22 11:56:57 EST 2023

all: more error cleanup

--- a/blk.c
+++ b/blk.c
@@ -9,7 +9,7 @@
 
 static vlong	blkalloc_lk(Arena*, int);
 static vlong	blkalloc(int, uint);
-static int	blkdealloc_lk(Arena*, vlong);
+static void	blkdealloc_lk(Arena*, vlong);
 static Blk*	initblk(Blk*, vlong, vlong, int);
 
 int
@@ -54,7 +54,7 @@
 	assert(b->bp.addr >= 0);
 	clrflag(b, Bdirty);
 	if(pwrite(fs->fd, b->buf, Blksz, b->bp.addr) == -1)
-		broke("%r");
+		broke("%s: %r", Eio);
 }
 
 static Blk*
@@ -65,8 +65,7 @@
 	Blk *b;
 
 	assert(bp != -1);
-	if((b = cachepluck()) == nil)
-		return nil;
+	b = cachepluck();
 	b->alloced = getcallerpc(&bp);
 	off = bp;
 	rem = Blksz;
@@ -73,7 +72,7 @@
 	while(rem != 0){
 		n = pread(fs->fd, b->buf, rem, off);
 		if(n <= 0)
-			error("%r");
+			error("%s: %r", Eio);
 		off += n;
 		rem -= n;
 	}
@@ -160,7 +159,7 @@
 	return &fs->arenas[i];
 }
 
-static int
+static void
 freerange(Avltree *t, vlong off, vlong len)
 {
 	Arange *r, *s;
@@ -167,7 +166,7 @@
 
 	assert(len % Blksz == 0);
 	if((r = calloc(1, sizeof(Arange))) == nil)
-		return -1;
+		error(Enomem);
 	r->off = off;
 	r->len = len;
 	assert(avllookup(t, r, 0) == nil);
@@ -174,7 +173,6 @@
 	avlinsert(t, r);
 
 Again:
-
 	s = (Arange*)avlprev(r);
 	if(s != nil && s->off+s->len == r->off){
 		avldelete(t, r);
@@ -192,10 +190,9 @@
 		r = s;
 		goto Again;
 	}
-	return 0;
 }
 
-static int
+static void
 grabrange(Avltree *t, vlong off, vlong len)
 {
 	Arange *r, *s, q;
@@ -214,8 +211,7 @@
 	}else if(off + len == r->off + r->len){
 		r->len -= len;
 	}else if(off > r->off && off+len < r->off + r->len){
-		if((s = malloc(sizeof(Arange))) == nil)
-			return -1;
+		s = emalloc(sizeof(Arange), 0);
 		l = r->len;
 		s->off = off + len;
 		r->len = off - r->off;
@@ -228,7 +224,6 @@
 		avldelete(t, r);
 		free(r);
 	}
-	return 0;
 }
 
 static Blk*
@@ -251,7 +246,7 @@
  * of the work in allocblk to prevent
  * recursion.
  */
-static int
+static void
 logappend(Arena *a, vlong off, vlong len, int op)
 {
 	vlong o;
@@ -283,10 +278,8 @@
 	 * and chaining.
 	 */
 	if(lb == nil || lb->logsz >= Logspc - Logslop){
-		if((o = blkalloc_lk(a, 1)) == -1)
-			return -1;
-		if((nl = mklogblk(a, o)) == nil)
-			return -1;
+		o = blkalloc_lk(a, 1);
+		nl = mklogblk(a, o);
 		p = lb->data + lb->logsz;
 		PACK64(p, o|LogAlloc1);
 		lb->logsz += 8;
@@ -314,10 +307,9 @@
 		PACK64(p+8, len);
 		lb->logsz += 8;
 	}
-	return 0;
 }
 
-int
+void
 loadlog(Arena *a, Bptr bp)
 {
 	vlong ent, off, len, gen;
@@ -328,8 +320,7 @@
 
 	dprint("loadlog %B\n", bp);
 	while(1){
-		if((b = getblk(bp, 0)) == nil)
-			return -1;
+		b = getblk(bp, 0);
 		dprint("\tload %B chain %B\n", bp, b->logp);
 		/* the hash covers the log and offset */
 		for(i = 0; i < b->logsz; i += n){
@@ -346,10 +337,10 @@
 					if(a->logtl == nil){
 						b->logsz = i;
 						a->logtl = holdblk(b);
-						return 0;
+						return;
 					}
 					dropblk(b);
-					return 0;
+					return;
 				}
 				break;
 	
@@ -357,8 +348,7 @@
 			case LogAlloc1:
 				len = (op >= Log2wide) ? UNPACK64(d+8) : Blksz;
 				dprint("\tlog@%d alloc: %llx+%llx\n", i, off, len);
-				if(grabrange(a->free, off & ~0xff, len) == -1)
-					return -1;
+				grabrange(a->free, off & ~0xff, len);
 				a->used += len;
 				break;
 			case LogFree:
@@ -365,10 +355,7 @@
 			case LogFree1:
 				len = (op >= Log2wide) ? UNPACK64(d+8) : Blksz;
 				dprint("\tlog@%d free: %llx+%llx\n", i, off, len);
-				if(freerange(a->free, off & ~0xff, len) == -1){
-					werrstr("invalid free: %r");
-					return -1;
-				}
+				freerange(a->free, off & ~0xff, len);
 				a->used -= len;
 				break;
 			default:
@@ -380,7 +367,7 @@
 		}
 		if(b->logp.addr == -1){
 			a->logtl = b;
-			return 0;
+			return;
 		}
 		bp = b->logp;
 		dropblk(b);
@@ -426,17 +413,17 @@
 	nblks = (sz+Logspc)/(Logspc - Logslop) + 16*nr/(Logspc-Logslop) + 1;
 	if((blks = calloc(nblks, sizeof(vlong))) == nil)
 		return -1;
-	for(i = 0; i < nblks; i++){
-		blks[i] = blkalloc_lk(a, 1);
-		if(blks[i] == -1)
-			return -1;
+	if(waserror()){
+		free(blks);
+		return -1;
 	}
+	for(i = 0; i < nblks; i++)
+		blks[i] = blkalloc_lk(a, 1);
 
 	/* fill up the log with the ranges from the tree */
 	i = 0;
 	hd = (Bptr){blks[0], -1, -1};
-	if((b = cachepluck()) == nil)
-		return -1;
+	b = cachepluck();
 	initblk(b, blks[i++], -1, Tlog);
 	for(r = (Arange*)avlmin(a->free); r != nil; r = (Arange*)avlnext(r)){
 		if(b->logsz >= Logspc - Logslop){
@@ -472,6 +459,7 @@
 		cachedel(b->bp.addr);
 		blkdealloc_lk(a, blks[i]);
 	}
+	free(blks);
 	return 0;
 }
 
@@ -478,8 +466,7 @@
 int
 syncbarrier(Arena *a, vlong gen)
 {
-	if(logappend(a, gen<<8, 0, LogSync) == -1)
-		return -1;
+	logappend(a, gen<<8, 0, LogSync);
 	if(a->loghd.addr == -1)
 		a->loghd = a->logtl->bp;
 	return 0;
@@ -503,7 +490,7 @@
 	if(!force && a->size - a->used <= a->reserve)
 		return -1;
 	if(r == nil)
-		broke(Efull);
+		broke(Estuffed);
 
 	/*
 	 * A bit of sleight of hand here:
@@ -523,35 +510,25 @@
 	return b;
 }
 
-static int
+static void
 blkdealloc_lk(Arena *a, vlong b)
 {
-	int r;
-
-	r = -1;
-	if(logappend(a, b, Blksz, LogFree) == -1)
-		return -1;
+	logappend(a, b, Blksz, LogFree);
 	if(a->loghd.addr == -1)
 		a->loghd = a->logtl->bp;
-	if(freerange(a->free, b, Blksz) == -1)
-		goto out;
+	freerange(a->free, b, Blksz);
 	a->used -= Blksz;
-	r = 0;
-out:
-	return r;
 }
 
-int
+void
 blkdealloc(vlong b)
 {
 	Arena *a;
-	int r;
 
 	a = getarena(b);
  	qlock(a);
-	r = blkdealloc_lk(a, b);
+	blkdealloc_lk(a, b);
 	qunlock(a);
-	return r;
 }
 
 static vlong
@@ -592,10 +569,7 @@
 		poperror();
 		goto Again;
 	}
-	if(logappend(a, b, Blksz, LogAlloc) == -1){
-		qunlock(a);
-		return -1;
-	}
+	logappend(a, b, Blksz, LogAlloc);
 	if(a->loghd.addr == -1)
 		a->loghd = a->logtl->bp;
 	qunlock(a);
@@ -647,15 +621,13 @@
 }
 
 Blk*
-newdblk(Tree *t, int ty, vlong hint)
+newblk(Tree *t, int ty, vlong hint)
 {
 	vlong bp;
 	Blk *b;
 
-	if((bp = blkalloc(ty, hint)) == -1)
-		return nil;
-	if((b = cachepluck()) == nil)
-		return nil;
+	bp = blkalloc(ty, hint);
+	b = cachepluck();
 	initblk(b, bp, t->memgen, ty);
 	b->alloced = getcallerpc(&t);
 	return b;
@@ -662,17 +634,11 @@
 }
 
 Blk*
-newblk(Tree *t, int ty)
-{
-	return newdblk(t, ty, 0);
-}
-
-Blk*
 dupblk(Tree *t, Blk *b)
 {
 	Blk *r;
 
-	if((r = newblk(t, b->type)) == nil)
+	if((r = newblk(t, b->type, 0)) == nil)
 		return nil;
 
 	setflag(r, Bdirty);
@@ -730,14 +696,18 @@
 getblk(Bptr bp, int flg)
 {
 	uvlong xh, ck;
-	char *t;
 	Blk *b;
 	int i;
 
 	i = ihash(bp.addr) % nelem(fs->blklk);
 	qlock(&fs->blklk[i]);
+	if(waserror()){
+		qunlock(&fs->blklk[i]);
+		nexterror();
+	}
 	if((b = cacheget(bp.addr)) != nil){
 		b->lasthold = getcallerpc(&bp);
+		poperror();
 		qunlock(&fs->blklk[i]);
 		return b;
 	}
@@ -746,24 +716,19 @@
 	b->bp.hash = blkhash(b);
 	if((flg&GBnochk) == 0){
 		if(b->type == Tlog || b->type == Tdlist){
-			t = "log";
 			xh = b->logh;
 			ck = bufhash(b->data, b->logsz);
 		}else{
-			t = "block";
 			xh = bp.hash;
 			ck = b->bp.hash;
 		}
-		if(ck != xh){
-			fprint(2, "corrupt %s %p %B: %.16llux != %.16llux\n",
-			t, b, bp, xh, ck);
-			qunlock(&fs->blklk[i]);
-			return nil;
-		}
+		if(ck != xh)
+			error("%s: %llx != %llx", Ecorrupt, xh, ck);
 	}
 	b->bp.gen = bp.gen;
 	b->lasthold = getcallerpc(&bp);
 	cacheins(b);
+	poperror();
 	qunlock(&fs->blklk[i]);
 
 	return b;
@@ -837,8 +802,7 @@
 		return;
 	}
 
-	if((f = malloc(sizeof(Bfree))) == nil)
-		abort();
+	f = emalloc(sizeof(Bfree), 0);
 	f->op = DFblk;
 	f->bp = bp;
 	f->b = nil;
@@ -966,8 +930,7 @@
 	q->emptyrz.l = &q->lk;
 	q->nheap = 0;
 	q->heapsz = fs->cmax;
-	if((q->heap = malloc(q->heapsz*sizeof(Qent))) == nil)
-		sysfatal("alloc queue: %r");
+	q->heap = emalloc(q->heapsz*sizeof(Qent), 1);
 
 }
 
--- a/dat.h
+++ b/dat.h
@@ -132,6 +132,8 @@
 
 /* internal errors */
 #define Efs	(abort(), "fs broke")
+extern char Ecorrupt[];
+extern char Efsvers[];
 extern char Eimpl[];
 extern char Ebotch[];
 extern char Eio[];
@@ -143,6 +145,7 @@
 extern char Eexist[];
 extern char Emode[];
 extern char Efull[];
+extern char Estuffed[];
 extern char Eauth[];
 extern char Elength[];
 extern char Eperm[];
--- a/dump.c
+++ b/dump.c
@@ -82,12 +82,10 @@
 		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);
+			kv2dir(v, &d);
+			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");
--- a/error.c
+++ b/error.c
@@ -4,6 +4,8 @@
 #include <fcall.h>
 #include "dat.h"
 
+char Ecorrupt[] = "block contents corrupted";
+char Efsvers[]	= "unknown fs version";
 char Eimpl[]	= "not implemented";
 char Ebotch[]	= "protocol botch";
 char Eio[]	= "i/o error";
@@ -15,6 +17,7 @@
 char Eexist[]	= "create/wstat -- file exists";
 char Emode[]	= "open/create -- unknown mode";
 char Efull[]	= "file system full";
+char Estuffed[]	= "emergency blocks exhausted";
 char Eauth[]	= "authentication failed";
 char Elength[]	= "name too long";
 char Eperm[]	= "permission denied";
--- a/fns.h
+++ b/fns.h
@@ -13,6 +13,8 @@
 extern char*	reamuser;
 extern void**	errctx;
 extern Blk*	blkbuf;
+extern int	noneid;
+extern int	nogroupid;
 
 #define	UNPACK8(p)	(((uchar*)(p))[0])
 #define	UNPACK16(p)	((((uchar*)(p))[0]<<8)|(((uchar*)(p))[1]))
@@ -29,8 +31,9 @@
 #define	PACK64(p,v)	do{(p)[0]=(v)>>56;(p)[1]=(v)>>48;(p)[2]=(v)>>40;(p)[3]=(v)>>32;\
 			   (p)[4]=(v)>>24;(p)[5]=(v)>>16;(p)[6]=(v)>>8;(p)[7]=(v);}while(0)
 
-Blk*	newdblk(Tree *, int, vlong);
-Blk*	newblk(Tree *, int);
+void*	emalloc(usize, int);
+
+Blk*	newblk(Tree *, int, vlong);
 Blk*	dupblk(Tree *, Blk*);
 Blk*	getroot(Tree*, int*);
 Blk*	getblk(Bptr, int);
@@ -56,9 +59,9 @@
 void	epochclean(void);
 void	limbo(Bfree*);
 void	freeblk(Tree*, Blk*, Bptr);
-int	dlappend(Dlist *dl, Bptr);
-int	killblk(Tree*, Bptr);
-int	blkdealloc(vlong);
+void	dlappend(Dlist *dl, Bptr);
+void	killblk(Tree*, Bptr);
+void	blkdealloc(vlong);
 ushort	blkfill(Blk*);
 uvlong	blkhash(Blk*);
 uvlong	bufhash(void*, usize);
@@ -77,10 +80,10 @@
 void	closesnap(Tree*);
 void	reamfs(char*);
 void	growfs(char*);
-int	loadarena(Arena*, Bptr, vlong);
+void	loadarena(Arena*, Bptr, vlong);
 void	loadfs(char*);
 void	sync(void);
-int	loadlog(Arena*, Bptr);
+void	loadlog(Arena*, Bptr);
 int	scandead(Dlist*, int, void(*)(Bptr, void*), void*);
 int	endfs(void);
 int	compresslog(Arena*);
@@ -151,7 +154,7 @@
 
 char*	packstr(char*, char*, char*);
 
-int	dir2kv(vlong, Xdir*, Kvp*, char*, int);
+void	dir2kv(vlong, Xdir*, Kvp*, char*, int);
 int	dir2statbuf(Xdir*, char*, int);
 void	dlist2kv(Dlist*, Kvp*, char*, int);
 void	lbl2kv(char*, vlong, uint, Kvp*, char*, int);
@@ -159,7 +162,7 @@
 void	retag2kv(vlong, vlong, int, int, Kvp*, char*, int);
 void	tree2kv(Tree*, Kvp*, char*, int);
 
-int	kv2dir(Kvp*, Xdir*);
+void	kv2dir(Kvp*, Xdir*);
 void	kv2dlist(Kvp*, Dlist*);
 void	kv2link(Kvp*, vlong*, vlong*);
 void	kv2qid(Kvp*, Qid*);
--- a/fs.c
+++ b/fs.c
@@ -25,8 +25,7 @@
 		return -1;
 	if(!btlookup(t, &k, &kv, rbuf, sizeof(rbuf)))
 		return -1;
-	if(kv2dir(&kv, &d) == -1)
-		return -1;
+	kv2dir(&kv, &d);
 	*qid = d.qid;
 	*len = d.length;
 	return 0;
@@ -329,7 +328,7 @@
 	PACK64(m->k+1, f->qpath);
 	PACK64(m->k+9, fb);
 
-	b = newdblk(f->mnt->root, Tdat, f->qpath);
+	b = newblk(f->mnt->root, Tdat, f->qpath);
 	t = nil;
 	if(lookup(f->mnt, m, &kv, buf, sizeof(buf))){
 		bp = unpackbp(kv.v, kv.nv);
@@ -688,7 +687,7 @@
 	return rpc;
 }
 
-static char*
+static void
 authread(Fid *f, Fcall *r, void *data, vlong count)
 {
 	AuthInfo *ai;
@@ -696,11 +695,11 @@
 	User *u;
 
 	if((rpc = f->auth) == nil)
-		return Etype;
+		error(Etype);
 
 	switch(auth_rpc(rpc, "read", nil, 0)){
 	default:
-		return Eauthp;
+		error(Eauthp);
 	case ARdone:
 		if((ai = auth_getinfo(rpc)) == nil)
 			goto Phase;
@@ -709,35 +708,34 @@
 		auth_freeAI(ai);
 		if(u == nil){
 			runlock(&fs->userlk);
-			return Enouser;
+			error(Enouser);
 		}
 		f->uid = u->id;
 		runlock(&fs->userlk);
-		return nil;
+		return;
 	case ARok:
 		if(count < rpc->narg)
-			return Eauthd;
+			error(Eauthd);
 		memmove(data, rpc->arg, rpc->narg);
 		r->count = rpc->narg;
-		return nil;
+		return;
 	case ARphase:
 	Phase:
-		return Eauthph;
+		error(Eauthph);
 	}
 }
 
-static char*
+static void
 authwrite(Fid *f, Fcall *r, void *data, vlong count)
 {
 	AuthRpc *rpc;
 
 	if((rpc = f->auth) == nil)
-		return Etype;
+		error(Etype);
 	if(auth_rpc(rpc, "write", data, count) != ARok)
-		return Ebotch;
+		error(Ebotch);
 	r->type = Rwrite;
 	r->count = count;
-	return nil;
 
 }
 
@@ -857,7 +855,7 @@
 	/* uid none gets only other permissions */
 	if(permissive)
 		return 0;
-	if(f->uid != 0) {
+	if(f->uid != noneid) {
 		if(f->uid == fuid)
 			if((m & (fmode>>6)) == m)
 				return 0;
@@ -868,7 +866,7 @@
 	if(m & fmode) {
 		if((fmode & DMDIR) && (m == DMEXEC))
 			return 0;
-		if(!ingroup(f->uid, 9999))
+		if(!ingroup(f->uid, nogroupid))
 			return 0;
 	}
 	return -1;
@@ -877,7 +875,7 @@
 static void
 fsattach(Fmsg *m)
 {
-	char *e, *p, *n, dbuf[Kvmax], kvbuf[Kvmax];
+	char *p, *n, dbuf[Kvmax], kvbuf[Kvmax];
 	Mount *mnt;
 	Dent *de;
 	Tree *t;
@@ -924,8 +922,7 @@
 			putfid(af);
 			nexterror();
 		}
-		if((e = authread(af, &r, nil, 0)) != nil)
-			error(e);
+		authread(af, &r, nil, 0);
 		if(af->uid != uid)
 			error(Ebadu);
 		poperror();
@@ -947,7 +944,7 @@
 		kv2dir(&kv, &d);
 	}
 	if((de = getdent(-1, &d)) == nil)
-		error(Efs);
+		broke(Efs);
 
 	memset(&f, 0, sizeof(Fid));
 	f.fid = NOFID;
@@ -1128,7 +1125,8 @@
 		return;
 	}
 	rlock(f->dent);
-	n = dir2statbuf(f->dent, buf, sizeof(buf));
+	if((n = dir2statbuf(f->dent, buf, sizeof(buf))) == -1)
+		error(Efs);
 	runlock(f->dent);
 	r.type = Rstat;
 	r.stat = (uchar*)buf;
@@ -1448,10 +1446,7 @@
 	d.muid = f->uid;
 
 	mb[nm].op = Oinsert;
-	if(dir2kv(f->qpath, &d, &mb[nm], buf, sizeof(buf)) == -1){
-		rerror(m, Efs);
-		goto Out;
-	}
+	dir2kv(f->qpath, &d, &mb[nm], buf, sizeof(buf));
 	nm++;
 
 	if(m->perm & DMDIR){
@@ -1666,7 +1661,7 @@
 	putfid(f);
 }
 
-static char*
+static void
 readsnap(Fmsg *m, Fid *f, Fcall *r)
 {
 	char pfx[1], *p;
@@ -1676,10 +1671,9 @@
 
 	s = f->scan;
 	if(s != nil && s->offset != 0 && s->offset != m->offset)
-		return Edscan;
+		error(Edscan);
 	if(s == nil || m->offset == 0){
-		if((s = mallocz(sizeof(Scan), 1)) == nil)
-			return Enomem;
+		s = emalloc(sizeof(Scan), 1);
 		pfx[0] = Klabel;
 		btnewscan(s, pfx, 1);
 		lock(f);
@@ -1691,7 +1685,7 @@
 	}
 	if(s->donescan){
 		r->count = 0;
-		return nil;
+		return;
 	}
 	p = r->data;
 	n = m->count;
@@ -1702,7 +1696,7 @@
 		d.qid.path = UNPACK64(s->kv.v + 1);
 		if((ns = dir2statbuf(&d, p, n)) == -1){
 			r->count = 0;
-			return nil;
+			return;
 		}
 		s->overflow = 0;
 		p += ns;
@@ -1724,10 +1718,10 @@
 	}
 	btexit(s);
 	r->count = p - r->data;
-	return nil;
+	return;
 }
 
-static char*
+static void
 readdir(Fmsg *m, Fid *f, Fcall *r)
 {
 	char pfx[Dpfxsz], *p;
@@ -1738,11 +1732,9 @@
 	s = f->scan;
 	t = agetp(&f->mnt->root);
 	if(s != nil && s->offset != 0 && s->offset != m->offset)
-		return Edscan;
+		error(Edscan);
 	if(s == nil || m->offset == 0){
-		if((s = mallocz(sizeof(Scan), 1)) == nil)
-			return Enomem;
-
+		s = emalloc(sizeof(Scan), 1);
 		packdkey(pfx, sizeof(pfx), f->qpath, nil);
 		btnewscan(s, pfx, sizeof(pfx));
 		lock(f);
@@ -1753,7 +1745,7 @@
 	}
 	if(s->donescan){
 		r->count = 0;
-		return nil;
+		return;
 	}
 	p = r->data;
 	n = m->count;
@@ -1760,7 +1752,7 @@
 	if(s->overflow){
 		if((ns = kv2statbuf(&s->kv, p, n)) == -1){
 			r->count = 0;
-			return nil;
+			return;
 		}
 		s->overflow = 0;
 		p += ns;
@@ -1779,10 +1771,9 @@
 	}
 	btexit(s);
 	r->count = p - r->data;
-	return nil;
 }
 
-static char*
+static void
 readfile(Fmsg *m, Fid *f, Fcall *r)
 {
 	vlong n, c, o;
@@ -1793,7 +1784,7 @@
 	rlock(e);
 	if(m->offset > e->length){
 		runlock(e);
-		return nil;
+		return;
 	}
 	p = r->data;
 	c = m->count;
@@ -1802,11 +1793,6 @@
 		c = e->length - m->offset;
 	while(c != 0){
 		n = readb(f, p, o, c, e->length);
-		if(n == -1){
-			fprint(2, "read %K [%Q]@%lld+%lld: %r\n", &e->Key, e->qid, o, c);
-			runlock(e);
-			return Efs;
-		}
 		r->count += n;
 		if(n == 0)
 			break;
@@ -1815,13 +1801,11 @@
 		c -= n;
 	}
 	runlock(e);
-	return nil;
 }
 
 static void
 fsread(Fmsg *m)
 {
-	char *e;
 	Fcall r;
 	Fid *f;
 
@@ -1831,24 +1815,25 @@
 	}
 	r.type = Rread;
 	r.count = 0;
-	if((r.data = malloc(m->count)) == nil){
-		rerror(m, Enomem);
+	r.data = nil;
+	if(waserror()){
+		rerror(m, errmsg());
+		free(r.data);
 		putfid(f);
 		return;
-	}
+	}	
+	r.data = emalloc(m->count, 0);
 	if(f->dent->qid.type & QTAUTH)
-		e = authread(f, &r, r.data, m->count);
+		authread(f, &r, r.data, m->count);
 	else if(f->dent->qid.path == Qdump)
-		e = readsnap(m, f, &r);
+		readsnap(m, f, &r);
 	else if(f->dent->qid.type & QTDIR)
-		e = readdir(m, f, &r);
+		readdir(m, f, &r);
 	else
-		e = readfile(m, f, &r);
-	if(e != nil)
-		rerror(m, e);
-	else
-		respond(m, &r);
+		readfile(m, f, &r);
+	respond(m, &r);
 	free(r.data);
+	poperror();
 	putfid(f);
 }
 
@@ -1859,8 +1844,8 @@
 	Bptr bp[Max9p/Blksz + 2];
 	Msg kv[Max9p/Blksz + 2];
 	vlong n, o, c, w;
-	char *p, *e;
 	int i, j;
+	char *p;
 	Fcall r;
 	Tree *t;
 	Fid *f;
@@ -1886,9 +1871,7 @@
 	if(f->dent->gone)
 		error(Ephase);
 	if(f->dent->qid.type == QTAUTH){
-		e = authwrite(f, &r, m->data, m->count);
-		if(e != nil)
-			error(e);
+		authwrite(f, &r, m->data, m->count);
 		goto Out;
 	}		
 
--- a/load.c
+++ b/load.c
@@ -16,7 +16,7 @@
 	return 0;
 }
 
-int
+void
 loadarena(Arena *a, Bptr hdbp, vlong asz)
 {
 	Blk *hd, *tl, *b;
@@ -24,31 +24,37 @@
 
 	/* try to load block pointers with consistency check */
 	bp = hdbp;
-	hd = getblk(bp, 0);
+	hd = nil;
+	tl = nil;
+	if(!waserror()){
+		hd = getblk(bp, 0);
+		poperror();
+	}
 	bp.addr += asz;
-	tl = getblk(bp, 0);
+	if(!waserror()){
+		tl = getblk(bp, 0);
+		poperror();
+	}
 
 	/* if neither head nor tail is consistent, we're hosed */
 	b = (hd != nil) ? hd : tl;
 	if(b == nil)
-		return -1;
+		error(Efs);
 
 	/* otherwise, we could have crashed mid-pass, just load the blocks */
 	bp = hdbp;
-	if(hd == nil && (hd = getblk(bp, GBnochk)) == nil)
-		return -1;
+	if(hd == nil)
+		hd = getblk(bp, GBnochk);
 	bp.addr += asz;
-	if(tl == nil && (tl = getblk(bp, GBnochk)) == nil)
-		return -1;
+	if(tl == nil)
+		tl = getblk(bp, GBnochk);
 
-	if(unpackarena(a, b->data, Arenasz) == nil)
-		return -1;
+	unpackarena(a, b->data, Arenasz);
 	if((a->free = avlcreate(rangecmp)) == nil)
-		return -1;
+		error(Enomem);
 	a->hd = hd;
 	a->tl = tl;
 	a->used = a->size;
-	return 0;
 }
 
 void
@@ -64,6 +70,8 @@
 		sysfatal("malloc: %r");
 	if((dump->name = strdup("dump")) == nil)
 		sysfatal("malloc: %r");
+	if(waserror())
+		sysfatal("load fs: %s", errmsg());
 	dump->ref = 1;
 	dump->gen = -1;
 	dump->root = &fs->snap;
@@ -74,20 +82,16 @@
 	if((fs->fd = open(dev, ORDWR)) == -1)
 		sysfatal("open %s: %r", dev);
 	bp = (Bptr){0, -1, -1};
-	if((fs->sb0 = getblk(bp, GBnochk)) == nil)
-		sysfatal("superblock: %r\n");
+	fs->sb0 = getblk(bp, GBnochk);
 	bp = (Bptr){512*MiB, -1, -1};
-	if((fs->sb1 = getblk(bp, GBnochk)) == nil)
-		sysfatal("superblock: %r\n");
-	if(unpacksb(fs, fs->sb0->buf, Blksz) == nil)
-		sysfatal("superblock: %r");
+	fs->sb1 = getblk(bp, GBnochk);
+	unpacksb(fs, fs->sb0->buf, Blksz);
 	if((fs->arenas = calloc(fs->narena, sizeof(Arena))) == nil)
 		sysfatal("malloc: %r");
 	for(i = 0; i < fs->narena; i++){
 		a = &fs->arenas[i];
 		memset(a, 0, sizeof(Arena));
-		if((loadarena(a, fs->arenabp[i], fs->arenasz)) == -1)
-			sysfatal("loadfs: %r");
+		loadarena(a, fs->arenabp[i], fs->arenasz);
 		a->reserve = a->size / 1024;
 		if(a->reserve < 32*MiB)
 			a->reserve = 32*MiB;
@@ -105,12 +109,9 @@
 		a->logbuf[1] = cachepluck();
 		a->logbuf[0]->bp = (Bptr){-1, -1, -1};
 		a->logbuf[1]->bp = (Bptr){-1, -1, -1};
-		if(loadlog(a, a->loghd) == -1)
-			sysfatal("load log %B: %r", a->loghd);
+		loadlog(a, a->loghd);
 	}
 
-	if(waserror())
-		sysfatal("load fs: %s\n", errmsg());
 	if((t = opensnap("adm", nil)) == nil)
 		sysfatal("load users: no adm label");
 	loadusers(2, t);
--- a/main.c
+++ b/main.c
@@ -17,9 +17,11 @@
 int	nproc;
 int	permissive;
 char	*reamuser;
-char	*srvname = "gefs";
 char	*dev;
-vlong	cachesz = 512*MiB;
+vlong	cachesz 	= 512*MiB;
+char	*srvname 	= "gefs";
+int	noneid		= 0;
+int	nogroupid	= 9999;
 Blk	*blkbuf;
 void	**errctx;
 
@@ -65,7 +67,6 @@
 	errorv(fmt, ap);
 }
 
-
 _Noreturn void
 nexterror(void)
 {
@@ -74,6 +75,16 @@
 	c = *errctx;
 	assert(c->nerrlab > 0 && c->nerrlab < Estacksz);
 	longjmp(c->errlab[--c->nerrlab], -1);
+}
+
+void*
+emalloc(usize sz, int zero)
+{
+	void *p;
+
+	if((p = mallocz(sz, zero)) == nil)
+		error(Enomem);
+	return p;
 }
 
 static void
--- a/pack.c
+++ b/pack.c
@@ -16,7 +16,7 @@
 		error(Elength);
 	n = UNPACK16(p);
 	if(e - p < n + 3 || p[n+2] != 0)
-		error(Efs);
+		broke(Efs);
 	*s = p+2;
 	return p+3+n;
 }
@@ -36,7 +36,7 @@
 	return p;
 }
 		
-int
+void
 dir2kv(vlong up, Xdir *d, Kvp *kv, char *buf, int nbuf)
 {
 	char *ek, *ev, *eb;
@@ -48,7 +48,6 @@
 	ev = packdval(ek, eb - ek, d);
 	kv->v = ek;
 	kv->nv = ev - ek;
-	return 0;
 }
 
 char*
@@ -112,7 +111,7 @@
 	return p;
 }
 
-int
+void
 kv2dir(Kvp *kv, Xdir *d)
 {
 	char *k, *ek, *v, *ev;
@@ -137,28 +136,26 @@
 	d->muid		= UNPACK32(v);	v += 4;
 	assert(v <= ev);
 	if(k != ek)
-		error(Efs);
+		broke(Efs);
 	if(v != ev)
-		error(Efs);
-	return 0;
+		broke(Efs);
 }
 
 int
 dir2statbuf(Xdir *d, char *buf, int nbuf)
 {
-	int sz, nn, nu, ng, nm, ret;
+	int sz, nn, nu, ng, nm;
 	vlong atime, mtime;
 	User *u, *g, *m;
 	char *p;
 
-	ret = -1;
 	rlock(&fs->userlk);
 	if((u = uid2user(d->uid)) == nil)
-		goto Out;
+		u = uid2user(noneid);
 	if((g = uid2user(d->gid)) == nil)
-		goto Out;
+		u = uid2user(nogroupid);
 	if((m = uid2user(d->muid)) == nil)
-		goto Out;
+		m = uid2user(noneid);
 
 	p = buf;
 	nn = strlen(d->name);
@@ -168,8 +165,10 @@
 	atime = (d->atime+Nsec/2)/Nsec;
 	mtime = (d->mtime+Nsec/2)/Nsec;
 	sz = STATFIXLEN + nn + nu + ng + nm;
-	if(sz > nbuf)
-		goto Out;
+	if(sz > nbuf){
+		runlock(&fs->userlk);
+		return -1;
+	}
 	
 	PBIT16(p, sz-2);		p += 2;
 	PBIT16(p, -1 /*type*/);		p += 2;
@@ -191,10 +190,8 @@
 	PBIT16(p, nm);			p += 2;
 	memcpy(p, m->name, nm);		p += nm;
 	assert(p - buf == sz);
-	ret = sz;
-Out:
 	runlock(&fs->userlk);
-	return ret;	
+	return sz;
 }
 
 int
@@ -467,10 +464,8 @@
 	int i;
 
 	assert(sz == Blksz);
-	if(memcmp(p, "gefs0008", 8) != 0){
-		werrstr("wrong block header %.8s\n", p);
-		return nil;
-	}
+	if(memcmp(p, "gefs0008", 8) != 0)
+		error("%s %.8s", Efsvers, p);
 	p += 8;
 	fi->blksz = UNPACK32(p);		p += 4;
 	fi->bufspc = UNPACK32(p);		p += 4;
--- a/ream.c
+++ b/ream.c
@@ -50,20 +50,16 @@
 
 	fillxdir(&d, Qadmuser, "users", QTFILE, 0664);
 	d.length = nu;
-	if(dir2kv(Qadmroot, &d, &kv, vbuf, sizeof(vbuf)) == -1)
-		sysfatal("ream: pack users: %r");
+	dir2kv(Qadmroot, &d, &kv, vbuf, sizeof(vbuf));
 	setval(r, &kv);
 	fillxdir(&d, Qadmroot, "", QTDIR, DMDIR|0775);
-	if(dir2kv(-1, &d, &kv, vbuf, sizeof(vbuf)) == -1)
-		sysfatal("ream: pack root: %r");
+	dir2kv(-1, &d, &kv, vbuf, sizeof(vbuf));
 	setval(r, &kv);
 
-	if((p = packsuper(kbuf, sizeof(kbuf), 0)) == nil)
-		sysfatal("ream: pack super");
+	p = packsuper(kbuf, sizeof(kbuf), 0);
 	kv.k = kbuf;
 	kv.nk = p - kbuf;
-	if((p = packdkey(vbuf, sizeof(vbuf), -1, "")) == nil)
-		sysfatal("ream: pack super");
+	p = packdkey(vbuf, sizeof(vbuf), -1, "");
 	kv.v = vbuf;
 	kv.nv = p - vbuf;
 	setval(r, &kv);
@@ -78,16 +74,13 @@
 
 	/* 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");
+	dir2kv(-1, &d, &kv, vbuf, sizeof(vbuf));
 	setval(r, &kv);
 
-	if((p = packsuper(kbuf, sizeof(kbuf), 0)) == nil)
-		sysfatal("ream: pack super");
+	p = packsuper(kbuf, sizeof(kbuf), 0);
 	kv.k = kbuf;
 	kv.nk = p - kbuf;
-	if((p = packdkey(vbuf, sizeof(vbuf), -1, "")) == nil)
-		sysfatal("ream: pack super");
+	p = packdkey(vbuf, sizeof(vbuf), -1, "");
 	kv.v = vbuf;
 	kv.nv = p - vbuf;
 	setval(r, &kv);
@@ -271,14 +264,10 @@
 
 	if(sz < 512*MiB+Blksz)
 		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");
+	mnt = emalloc(sizeof(Mount), 1);
+	mnt->root = mallocz(sizeof(Tree), 1);
+	adm = mallocz(sizeof(Mount), 1);
+	adm->root = mallocz(sizeof(Tree), 1);
 
 	sz = sz - sz%Blksz - 2*Blksz;
 
@@ -287,8 +276,7 @@
 		fs->narena = 8;
 	if(fs->narena >= 128)
 		fs->narena = 128;
-	if((fs->arenas = calloc(fs->narena, sizeof(Arena))) == nil)
-		sysfatal("malloc: %r");
+	fs->arenas = emalloc(fs->narena*sizeof(Arena), 1);
 
 
 	off = Blksz;
@@ -301,7 +289,7 @@
 	sb0->bp = (Bptr){0, -1, -1};
 	sb1->bp = (Bptr){512*MiB, -1, -1};
 
-	fs->arenabp = malloc(fs->narena * sizeof(Bptr));
+	fs->arenabp = emalloc(fs->narena * sizeof(Bptr), 1);
 	for(i = 0; i < fs->narena; i++){
 		a = &fs->arenas[i];
 		print("\tarena %d: %lld blocks at %llx\n", i, asz/Blksz, off);
@@ -312,13 +300,11 @@
 	
 	for(i = 0; i < fs->narena; i++){
 		a = &fs->arenas[i];
-		if((loadarena(a, a->hd->bp, asz)) == -1)
-			sysfatal("ream: loadarena: %r");
-		if(loadlog(a, a->loghd) == -1)
-			sysfatal("load log: %r");
+		loadarena(a, a->hd->bp, asz);
+		loadlog(a, a->loghd);
 	}
 
-	if((mb = newblk(mnt->root, Tleaf)) == nil)
+	if((mb = newblk(mnt->root, Tleaf, 0)) == nil)
 		sysfatal("ream: allocate root: %r");
 	holdblk(mb);
 	initroot(mb);
@@ -328,9 +314,9 @@
 	mnt->root->ht = 1;
 	mnt->root->bp = mb->bp;
 
-	if((ab = newblk(adm->root, Tleaf)) == nil)
+	if((ab = newblk(adm->root, Tleaf, 0)) == nil)
 		sysfatal("ream: allocate root: %r");
-	if((ub = newblk(adm->root, Tdat)) == nil)
+	if((ub = newblk(adm->root, Tdat, 0)) == nil)
 		sysfatal("ream: allocate root: %r");
 	holdblk(ab);
 	holdblk(ub);
@@ -356,7 +342,7 @@
 	 * a single snap block that the tree will insert
 	 * into, and take a snapshot as the initial state.
 	 */
-	if((tb = newblk(mnt->root, Tleaf)) == nil)
+	if((tb = newblk(mnt->root, Tleaf, 0)) == nil)
 		sysfatal("ream: allocate snaps: %r");
 	holdblk(tb);
 	initsnap(tb, mb, ab);
@@ -444,8 +430,7 @@
 		sysfatal("malloc: %r");
 	for(i = 0; i < fs->narena; i++){
 		a = &fs->arenas[i];
-		if((loadarena(a, fs->arenabp[i], fs->arenasz)) == -1)
-			sysfatal("growfs: %r");
+		loadarena(a, fs->arenabp[i], fs->arenasz);
 	}
 	narena = sz/fs->arenasz;
 	off = fs->arenasz * fs->narena;
@@ -452,15 +437,14 @@
 	if(narena <= fs->narena)
 		sysfatal("disk too small for more arenas");
 	if((fs->arenas = realloc(fs->arenas, narena*sizeof(Arena))) == nil)
-		sysfatal("malloc: %r");
+		error(Enomem);
 	if((fs->arenabp = realloc(fs->arenas, narena*sizeof(Bptr))) == nil)
-		sysfatal("malloc: %r");
+		error(Enomem);
 	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], off, fs->arenasz);
-		if((loadarena(a, fs->arenabp[i], fs->arenasz)) == -1)
-			sysfatal("growfs: %r");
+		loadarena(a, fs->arenabp[i], fs->arenasz);
 		fs->arenabp[i] = a->hd->bp;
 		off += fs->arenasz;
 	}
--- a/snap.c
+++ b/snap.c
@@ -80,8 +80,7 @@
 
 	if((dl = dlcacheget(gen, bgen)) != nil)
 		return dl;
-	if((dl = mallocz(sizeof(Dlist), 1)) == nil)
-		error(Enomem);
+	dl = emalloc(sizeof(Dlist), 1);
 	if(waserror()){
 		free(dl);
 		nexterror();
@@ -124,8 +123,9 @@
 {
 	Dlist *dt;
 
+	if(dl == &fs->snapdl)
+		return;
 	dlcachedel(dl, 0);
-
 	while(fs->dltail != nil && fs->dlcount >= fs->dlcmax){
 		dt = fs->dltail;
 		dlsync(dt);
@@ -344,8 +344,7 @@
 		nexterror();
 	}
 	if(mutable){
-		if((n = mallocz(sizeof(Tree), 1)) == nil)
-			error(Enomem);
+		n = emalloc(sizeof(Tree), 1);
 		n->memref = 1;
 		n->dirty = 0;
 		n->nlbl = 1;
@@ -409,8 +408,7 @@
 
 	/* create the new one */
 
-	if((t = mallocz(sizeof(Tree), 1)) == nil)
-		error(Enomem);
+	t = emalloc(sizeof(Tree), 1);
 	if(waserror()){
 		free(t);
 		nexterror();
@@ -483,8 +481,7 @@
 	if(mut != nil)
 		*mut = !!(flg&Lmut);
 
-	if((t = mallocz(sizeof(Tree), 1)) == nil)
-		error(Enomem);
+	t = mallocz(sizeof(Tree), 1);
 	if(waserror()){
 		free(t);
 		nexterror();
@@ -512,8 +509,7 @@
 
 	if(t == nil || adec(&t->memref) != 0)
 		return;
-	if((f = malloc(sizeof(Bfree))) == nil)
-		abort();
+	f = malloc(sizeof(Bfree));
 	f->op = DFtree;
 	f->t = t;
 	limbo(f);
@@ -548,7 +544,7 @@
  * t must be an active snapshot with
  * no successors.
  */
-int
+void
 killblk(Tree *t, Bptr bp)
 {
 	Dlist *dl;
@@ -555,18 +551,23 @@
 	Blk *b;
 	char *p;
 
-	/* leak it and let the full collection clean it up */
+	/* 
+	 * When we have a forked snap, blocks allocated before the fork
+	 * are the responsibility of the other chain; in this chain, we
+	 * leak it and let the last reference in the other chain clean up
+	 */
 	if(bp.gen <= t->base)
-		return 0;
+		return;
 	if(t == &fs->snap)
 		dl = &fs->snapdl;
-	else if((dl = getdl(t->gen, bp.gen)) == nil)
- 		return -1;
+	else
+		dl = getdl(t->gen, bp.gen);
+	if(waserror()){
+		putdl(dl);
+		nexterror();
+	}
 	if(dl->ins == nil || Logspc - dl->ins->logsz < Logslop){
-		if((b = newblk(&fs->snap, Tdlist)) == nil){
-			putdl(dl);
-			return -1;
-		}
+		b = newblk(&fs->snap, Tdlist, 0);
 		if(dl->ins != nil)
 			enqueue(dl->ins);
 		if(dl->tl.addr == -1)
@@ -580,7 +581,6 @@
 	dl->ins->logsz += 8;
 	setflag(dl->ins, Bdirty);
 	PACK64(p, bp.addr);
-	if(t != &fs->snap)
-		putdl(dl);
-	return 0;
+	poperror();
+	putdl(dl);
 }
--- a/tree.c
+++ b/tree.c
@@ -482,7 +482,7 @@
 	 */
 	full = 0;
 	spc = Leafspc - blkfill(b);
-	n = newblk(t, b->type);
+	n = newblk(t, b->type, 0);
 	assert(i >= 0 && j >= 0);
 	while(i < b->nval){
 		ok = 1;
@@ -573,7 +573,7 @@
 	Msg m, u;
 
 	b = p->b;
-	n = newblk(t, b->type);
+	n = newblk(t, b->type, 0);
 	for(i = 0; i < b->nval; i++){
 		if(pp != nil && i == p->midx){
 			copyup(n, pp, nil);
@@ -656,8 +656,8 @@
 		efreeblk(t, r);
 		nexterror();
 	}
-	l = newblk(t, b->type);
-	r = newblk(t, b->type);
+	l = newblk(t, b->type, 0);
+	r = newblk(t, b->type, 0);
 
 	d = l;
 	i = 0;
@@ -754,8 +754,8 @@
 		efreeblk(t, r);
 		nexterror();
 	}
-	l = newblk(t, b->type);
-	r = newblk(t, b->type);
+	l = newblk(t, b->type, 0);
+	r = newblk(t, b->type, 0);
 	d = l;
 	copied = 0;
 	halfsz = (2*b->nval + b->valsz)/2;
@@ -804,7 +804,7 @@
 	Msg m;
 	int i;
 
-	d = newblk(t, a->type);
+	d = newblk(t, a->type, 0);
 	for(i = 0; i < a->nval; i++){
 		getval(a, i, &m);
 		setval(d, &m);
@@ -888,8 +888,8 @@
 		efreeblk(t, r);
 		nexterror();
 	}
-	l = newblk(t, a->type);
-	r = newblk(t, a->type);
+	l = newblk(t, a->type, 0);
+	r = newblk(t, a->type, 0);
 	d = l;
 	cp = 0;
 	sp = -1;
@@ -1073,7 +1073,7 @@
 	}
 	if(pp->nl != nil && pp->nr != nil){
 		rp = &path[0];
-		rp->nl = newblk(t, Tpivot);
+		rp->nl = newblk(t, Tpivot, 0);
 		rp->npull = pp->npull;
 		rp->pullsz = pp->pullsz;
 		copyup(rp->nl, pp, nil);
@@ -1222,7 +1222,6 @@
 		freepath(t, path, npath);
 		nexterror();
 	}
-int eb;
 
 Again:
 	b = getroot(t, &height);
--- a/user.c
+++ b/user.c
@@ -125,15 +125,18 @@
 			err = Esyntax;
 			goto Error;
 		}
-		users[i].id = atol(f);
+		u = &users[i];
+		u->id = atol(f);
 		if((f = getfield(&p, ':')) == nil){
 			fprint(fd, "/adm/users:%d: missing ':' after name\n", lnum);
 			err = Esyntax;
 			goto Error;
 		}
-		snprint(users[i].name, sizeof(users[i].name), "%s", f);
-		users[i].memb = nil;
-		users[i].nmemb = 0;
+		snprint(u->name, sizeof(u->name), "%s", f);
+		u->memb = nil;
+		u->nmemb = 0;
+		if(strcmp(u->name, "none") == 0)
+			noneid = u->id;
 		i++;
 	}
 	nusers = i;
@@ -190,6 +193,8 @@
 			}
 			grp = g;
 			grp[ngrp++] = u->id;
+			if(strcmp(u->name, "nogroup") == 0)
+				nogroupid = u->id;
 		}
 		users[i].memb = grp;
 		users[i].nmemb = ngrp;