git: 9front

Download patch

ref: a81e1c90c2a8e2e38111f098faca167dd0f58fd4
parent: 421b1cc87b0a7ad10548b220b108e2291bfe36f0
author: Ori Bernstein <ori@eigenstate.org>
date: Mon Feb 9 18:51:00 EST 2026

gefs: don't go read-only when recovering from broken arena header

broken arena headers are an expected and recoverable outcome
of crashing while in the middle of syncing an arena; we have
a commit protocol that looks like:

	initial     # header v0, data v0, footer v0
	updatehdr   # header v1, data v0, footer v0
	syncdata    # header v1, data v1, footer v0
	updatefoot  # header v1, data v1, footer v1

when the version of the header or footer is out of sync, we
detect the mismatch and whine.

--- a/sys/src/cmd/gefs/blk.c
+++ b/sys/src/cmd/gefs/blk.c
@@ -79,7 +79,7 @@
 	b->type = (flg&GBraw) ? Tdat : UNPACK16(b->buf+0);
 	switch(b->type){
 	default:
-		broke("invalid block type %d @%llx", b->type, bp);
+		error("invalid block type %d @%llx", b->type, bp);
 		break;
 	case Tdat:
 	case Tsuper:
@@ -119,7 +119,7 @@
 		ck = blkhash(b);
 	}
 	if((flg&GBnochk) == 0 && ck != xh)
-		broke("%s: %ullx %llux != %llux", Ecorrupt, bp.addr, xh, ck);
+		error("%s: %ullx %llux != %llux", Ecorrupt, bp.addr, xh, ck);
 	bassert(b, b->magic == Magic);
 }
 
@@ -734,6 +734,10 @@
 	qlock(&fs->blklk[i]);
 	if(waserror()){
 		qunlock(&fs->blklk[i]);
+		if(flg&GBtry)
+			return nil;
+		else
+			aincl(&fs->rdonly, 1);
 		nexterror();
 	}
 	if((b = cacheget(bp.addr)) != nil){
--- a/sys/src/cmd/gefs/dat.h
+++ b/sys/src/cmd/gefs/dat.h
@@ -276,6 +276,7 @@
 	GBraw	= 1<<0,
 	GBwrite	= 1<<1,
 	GBnochk	= 1<<2,
+	GBtry	= 1<<3,
 };
 
 enum {
--- a/sys/src/cmd/gefs/load.c
+++ b/sys/src/cmd/gefs/load.c
@@ -22,26 +22,18 @@
 	Blk *h0, *h1, *b;
 	Bptr bp;
 
-	/* try to load block pointers with consistency check */
+	/* try to load block pointers, we only need one to succeed */
 	bp = hd;
-	h0 = nil;
-	h1 = nil;
-	if(!waserror()){
-		h0 = getblk(bp, 0);
-		poperror();
-	}else
-		fprint(2, "loading arena primary header: %s\n", errmsg());
+	h0 = getblk(bp, GBtry);
 	bp.addr += Blksz;
-	if(!waserror()){
-		h1 = getblk(bp, 0);
-		poperror();
-	}else
-		fprint(2, "loading arena backup header: %s\n", errmsg());
-
+	h1 = getblk(bp, GBtry);
 	/* if neither head nor tail is consistent, we're hosed */
 	b = (h0 != nil) ? h0 : h1;
 	if(b == nil)
 		error(Efs);
+	if(h0 == nil || h1 == nil)
+		fprint(2, "using fallback arena header %B\n", b->bp);
+
 
 	/* otherwise, we could have crashed mid-pass, just load the blocks */
 	bp = hd;
--