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){
--
⑨