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;
--
⑨