ref: 609d8e27749a12c41f527bbc43afe2b66f01449c
parent: 51d16fc61273db6d88691e9777066b70cbb397a1
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Dec 23 15:52:31 EST 2023
blk: take consistent snapshot under mutlk before syncing
--- a/blk.c
+++ b/blk.c
@@ -1070,14 +1070,13 @@
}
}
-vlong
+void
wrbarrier(void)
{
Qent qe;
- vlong gen;
int i;
- gen = aincv(&fs->qgen, 1);
+ aincv(&fs->qgen, 1);
fs->syncing = fs->nsyncers;
for(i = 0; i < fs->nsyncers; i++){
qe.op = Qfence;
@@ -1089,13 +1088,11 @@
}
while(fs->syncing != 0)
rsleep(&fs->syncrz);
- return gen;
}
void
sync(void)
{
- uvlong gen;
Arena *a;
int i;
@@ -1112,31 +1109,49 @@
qunlock(&fs->synclk);
nexterror();
}
+
+ /*
+ * pass 0: Pack the blocks we want to sync
+ * while holding the write lock, and then
+ * wait until all the blocks they point at
+ * have hit disk; once they're on disk, we
+ * can take a consistent snapshot.
+ */
+ qlock(&fs->mutlk);
flushdlcache(1);
- gen = wrbarrier();
- /* pass 0: sync arena contents */
for(i = 0; i < fs->narena; i++){
a = &fs->arenas[i];
qlock(a);
- logbarrier(a, gen);
setflag(a->logtl, Bdirty);
enqueue(a->logtl);
+ logbarrier(a, fs->qgen);
+
+ packarena(a->h0->data, Blksz, a);
+ packarena(a->h1->data, Blksz, a);
+ finalize(a->h0);
+ finalize(a->h1);
+ setflag(a->h0, Bdirty);
+ setflag(a->h1, Bdirty);
+ fs->arenabp[i] = a->h0->bp;
qunlock(a);
}
+
+ packsb(fs->sb0->buf, Blksz, fs);
+ packsb(fs->sb1->buf, Blksz, fs);
+ finalize(fs->sb0);
+ finalize(fs->sb1);
+ fs->snap.dirty = 0;
+ qunlock(&fs->mutlk);
+ wrbarrier();
/*
* pass 1: sync block headers; if we crash here,
* the block footers are consistent, and we can
* use them.
- */
- for(i = 0; i < fs->narena; i++){
- a = &fs->arenas[i];
- qlock(a);
- packarena(a->h0->data, Blksz, a);
- setflag(a->h0, Bdirty);
- enqueue(a->h0);
- qunlock(a);
- }
+ */ wrbarrier();
+ for(i = 0; i < fs->narena; i++)
+ enqueue(fs->arenas[i].h0);
wrbarrier();
+
/*
* pass 2: sync superblock; we have a consistent
* set of block headers, so if we crash, we can
@@ -1144,28 +1159,17 @@
* get synced after so that we can use them next
* time around.
*/
- for(i = 0; i < fs->narena; i++)
- fs->arenabp[i] = fs->arenas[i].h0->bp;
- packsb(fs->sb0->buf, Blksz, fs);
- packsb(fs->sb1->buf, Blksz, fs);
- finalize(fs->sb0);
- finalize(fs->sb1);
syncblk(fs->sb0);
syncblk(fs->sb1);
- fs->snap.dirty = 0;
+
/*
* pass 3: sync block footers; if we crash here,
* the block headers are consistent, and we can
* use them.
*/
- for(i = 0; i < fs->narena; i++){
- a = &fs->arenas[i];
- qlock(a);
- packarena(a->h1->data, Blksz, a);
- setflag(a->h1, Bdirty);
- enqueue(a->h1);
- qunlock(a);
- }
+ for(i = 0; i < fs->narena; i++)
+ enqueue(fs->arenas[i].h1);
+
/*
* Pass 4: clean up the old snap tree's deadlist
*/
--- a/fs.c
+++ b/fs.c
@@ -2277,10 +2277,11 @@
}
epochstart(id);
snapfs(am, &t);
- sync();
epochend(id);
poperror();
qunlock(&fs->mutlk);
+
+ sync();
if(t != nil){
epochwait();
--- a/load.c
+++ b/load.c
@@ -30,13 +30,13 @@
h0 = getblk(bp, 0);
poperror();
}else
- print("error %s\n", errmsg());
+ print("loading arena primary header: %s\n", errmsg());
bp.addr += Blksz;
if(!waserror()){
h1 = getblk(bp, 0);
poperror();
}else
- print("error %s\n", errmsg());
+ print("loading arena backup header: %s\n", errmsg());
/* if neither head nor tail is consistent, we're hosed */
b = (h0 != nil) ? h0 : h1;