shithub: front

Download patch

ref: e3426b3cdc6e883eeea5e5f4448b1ea5b3441050
parent: 2306dc88df5182cb8cbe84a7f5bc02f87c1ce16e
author: Ori Bernstein <ori@eigenstate.org>
date: Mon Jun 30 13:49:56 EDT 2025

gefs: handle full disk and other errors more gracefully

if we had a full disk, or failed upserting, we could have
double-freed disk blocks on retry. This forces us to stop
writing, eliminating the chance for retry

This should also be safe after a restart -- because sync
refuses to write to disk after a failure, we will roll
back the free operations on failure, and start from the
last successful sync.

There may still be some issues if the second superblock
fails during a disk failure, but the window for issues
is much narrower.

--- a/sys/src/cmd/gefs/fs.c
+++ b/sys/src/cmd/gefs/fs.c
@@ -88,6 +88,8 @@
 	Dlist dl;
 	int i;
 
+	if(agetl(&fs->rdonly))
+		error(Erdonly);
 	qlock(&fs->synclk);
 	if(waserror()){
 		fprint(2, "failed to sync: %s\n", errmsg());
@@ -110,6 +112,7 @@
          */
 	qlock(&fs->mutlk);
 	if(waserror()){
+		aincl(&fs->rdonly, 1);
 		qunlock(&fs->mutlk);
 		nexterror();
 	}
--- a/sys/src/cmd/gefs/tree.c
+++ b/sys/src/cmd/gefs/tree.c
@@ -3,6 +3,7 @@
 #include <fcall.h>
 #include <avl.h>
 
+#include "atomic.h"
 #include "dat.h"
 #include "fns.h"
 
@@ -1126,14 +1127,14 @@
 }
 
 static void
-freepath(Tree *t, Path *path, int npath)
+freepath(Tree *t, Path *path, int npath, int ok)
 {
 	Path *p;
 
 	for(p = path; p != path + npath; p++){
-		if(p->b != nil)
+		if(ok && p->b != nil)
 			freeblk(t, p->b);
-		if(p->m != nil)
+		if(ok && p->m != nil)
 			freeblk(t, p->b);
 		dropblk(p->b);
 		dropblk(p->nl);
@@ -1254,6 +1255,8 @@
 	Bptr bp;
 
 	assert(!canqlock(&fs->mutlk));
+	if(agetl(&fs->rdonly))
+		error(Erdonly);
 	sz = 0;
 	stablesort(msg, nmsg);
 	for(i = 0; i < nmsg; i++)
@@ -1262,6 +1265,7 @@
 Again:
 	b = getroot(t, &height);
 	if(waserror()){
+		aincl(&fs->rdonly, 1);
 		dropblk(b);
 		nexterror();
 	}
@@ -1279,7 +1283,7 @@
 		error(Enomem);
 	poperror();
 	if(waserror()){
-		freepath(t, path, height+2);	/* npath not volatile */
+		freepath(t, path, height+2, 0);	/* npath not volatile */
 		nexterror();
 	}
 	npath = 0;
@@ -1334,7 +1338,7 @@
 	unlock(&t->lk);
 
 	npull += rp->npull;
-	freepath(t, path, npath);
+	freepath(t, path, npath, 1);
 	poperror();
 
 	if(npull != nmsg){
--