ref: f4834c699a4e3c1782aeefe85e6e48e7473e505a
parent: 3147291a2c825c506f56f3bd77656a7d84cc1677
author: Ori Bernstein <ori@eigenstate.org>
date: Mon Nov 6 10:56:50 EST 2023
gefs: fix snapshot deletion
--- a/cons.c
+++ b/cons.c
@@ -78,7 +78,7 @@
na--;
ap++;
}
- if(a->delete && na != 1 || na != 2){
+ if(a->delete && na != 1 || !a->delete && na != 2){
fprint(fd, "usage: snap -[md] old [new]\n");
free(a);
return;
--- a/dat.h
+++ b/dat.h
@@ -62,8 +62,8 @@
Dlksz = 1+8+8, /* tag, death, birth */
Dlvsz = Ptrsz+Ptrsz, /* hd,tl of deadlist */
Dlkvpsz = Dlksz+Dlvsz, /* full size of dlist kvp */
- Linksz = 1+8+8, /* gen, prev of snap */
- Treesz = 4+4+4+4+8+8+8+Ptrsz, /* ref, ht, flg, gen, prev, base, root */
+ Treesz = 4+4+4+4 /* ref, ht, flg, gen, pred, succ, base, root */
+ +8+8+8+8+Ptrsz,
Kvmax = Keymax + Inlmax, /* Key and value */
Kpmax = Keymax + Ptrsz, /* Key and pointer */
Wstatmax = 4+8+8+8, /* mode, size, atime, mtime */
@@ -103,7 +103,6 @@
Ktref, /* tag[8] = snapid[] scratch snapshot label */
Ksnap, /* sid[8] => ref[8], tree[52]: snapshot root */
Kdlist, /* snap[8] gen[8] => hd[ptr],tl[ptr] deadlist */
- Kslink, /* snap[8] next[8] => [] snap successor list */
};
enum {
@@ -405,13 +404,14 @@
int dirty;
/* on-disk */
- int nsucc; /* number snapshots after us */
+ int nref; /* number snapshots forked/after us */
int nlbl; /* number of labels referring to us */
int ht; /* height of the tree */
uint flag; /* flag set */
Bptr bp; /* block pointer of root */
vlong gen; /* generation */
- vlong prev; /* previous snapshot */
+ vlong pred; /* previous snapshot */
+ vlong succ; /* next snapshot */
vlong base; /* base snapshot */
Msg mq[64];
--- a/dump.c
+++ b/dump.c
@@ -37,9 +37,6 @@
case Kup: /* qid[8] => pqid[8]: parent dir */
n = fmtprint(fmt, "up dir:%llx", UNPACK64(k->k+1));
break;
- case Kslink:
- n = fmtprint(fmt, "slink gen:%llx, succ:%llx", UNPACK64(k->k+1), UNPACK64(k->k+9));
- break;
case Kdlist:
n = fmtprint(fmt, "dlist gen:%llx, bgen:%llx", UNPACK64(k->k+1), UNPACK64(k->k+9));
break;
@@ -145,9 +142,6 @@
case Kup: /* qid[8] => pqid[8]: parent dir */
n = fmtprint(fmt, "super dir:%llx, name:\"%.*s\")", UNPACK64(v->v+1), v->nv-11, v->v+11);
break;
- case Kslink:
- n = fmtprint(fmt, "()");
- break;
case Kdlist:
n = fmtprint(fmt, "hd:%B, tl:%B", unpackbp(v->v, v->nv), unpackbp(v->v+Ptrsz, v->nv-Ptrsz));
break;
@@ -356,8 +350,9 @@
fprint(fd, "\tflag\t0x%x\n", t->flag);
fprint(fd, "\tgen:\t%lld\n", t->gen);
fprint(fd, "\tbase\t%lld\n", t->base);
- fprint(fd, "\tprev:\t%lld\n", t->prev);
- fprint(fd, "\tnsucc:\t%d\n", t->nsucc);
+ fprint(fd, "\tpred:\t%lld\n", t->pred);
+ fprint(fd, "\tpred:\t%lld\n", t->succ);
+ fprint(fd, "\tnref:\t%d\n", t->nref);
fprint(fd, "\tnlbl:\t%d\n", t->nlbl);
fprint(fd, "\tht:\t%d\n", t->ht);
fprint(fd, "\tbp:\t%B\n", t->bp);
@@ -474,7 +469,7 @@
fprint(fd, "broken: %B\n", hd);
break;
}
- fprint(fd, "logsz: %xm logp=%B\n", b->logsz, b->logp);
+ fprint(fd, "logsz: %x logp=%B\n", b->logsz, b->logp);
e = b->data + b->logsz;
for(p = b->data; p != e; p += 8)
fprint(fd, "\tdead: %llx\n", UNPACK64(p));
--- a/fns.h
+++ b/fns.h
@@ -71,7 +71,6 @@
char* delsnap(Tree*, vlong, char*);
char* freedl(Dlist*, int);
Tree* opensnap(char*, int*);
-vlong successor(vlong);
void closesnap(Tree*);
void reamfs(char*);
@@ -144,7 +143,7 @@
void dlist2kv(Dlist*, Kvp*, char*, int);
void lbl2kv(char*, vlong, uint, Kvp*, char*, int);
void link2kv(vlong, vlong, Kvp*, char*, int);
-void retag2kv(vlong, int, int, Kvp*, char*, int);
+void retag2kv(vlong, vlong, vlong, int, int, Kvp*, char*, int);
void tree2kv(Tree*, Kvp*, char*, int);
int kv2dir(Kvp*, Xdir*);
--- a/fs.c
+++ b/fs.c
@@ -36,7 +36,7 @@
static void
snapfs(Amsg *a)
{
- Mount *mnt;
+ Mount *mnt, *old;
vlong succ;
Tree *t, *s;
char *e;
@@ -57,13 +57,12 @@
return;
}
if(a->delete){
- succ = successor(t->gen);
- if(t != nil) {
- fprint(a->fd, "snap: snap in use: '%s'\n", a->old);
+ if(mnt != nil) {
+ fprint(a->fd, "snap: snap is mounted: '%s'\n", a->old);
unlock(&fs->mountlk);
return;
}
- if((e = delsnap(t, succ, a->old)) != nil){
+ if((e = delsnap(t, t->succ, a->old)) != nil){
fprint(a->fd, "snap: error deleting '%s': %s\n", a->new, e);
unlock(&fs->mountlk);
return;
@@ -255,7 +254,7 @@
if(!mnt->mutable)
return Erdonly;
- if(mnt->root->nlbl != 1 || mnt->root->nsucc != 0)
+ if(mnt->root->nlbl != 1 || mnt->root->nref != 0)
if((e = updatesnap(&mnt->root, mnt->root, mnt->name)) != nil)
return e;
return btupsert(mnt->root, m, nm);
--- a/pack.c
+++ b/pack.c
@@ -398,51 +398,26 @@
}
void
-retag2kv(vlong gen, int dlbl, int dsucc, Kvp *kv, char *buf, int nbuf)
+retag2kv(vlong gen, vlong pred, vlong succ, int dlbl, int dref, Kvp *kv, char *buf, int nbuf)
{
char *p;
+ assert(nbuf >= 8+8+1+1);
kv->k = buf;
if((p = packsnap(buf, nbuf, gen)) == nil)
abort();
kv->nk = p - buf;
- kv->v = p;
- p[0] = dlbl;
- p[1] = dsucc;
- kv->nv = 2;
-}
-void
-link2kv(vlong gen, vlong succ, Kvp *kv, char *buf, int nbuf)
-{
- char *p;
-
- assert(nbuf >= Linksz);
-
- p = buf;
- kv->k = p;
- *p++ = Kslink;
- PACK64(p, gen); p += 8;
- PACK64(p, succ); p += 8;
- kv->nk = (p - kv->k);
kv->v = p;
- kv->nv = 0;
+ PACK64(p, pred); p += 8;
+ PACK64(p, succ); p += 8;
+ *p = dlbl; p += 1;
+ *p = dref; p += 1;
+ kv->nv = p - kv->v;
+assert(kv->nv == 18);
}
void
-kv2link(Kvp *kv, vlong *gen, vlong *succ)
-{
- char *p;
-
- assert(kv->nk >= Linksz);
- assert(kv->nv == 0);
-
- p = kv->k+1;
- *gen = UNPACK64(p); p += 8;
- *succ = UNPACK64(p); //p += 8;
-}
-
-void
lbl2kv(char *lbl, vlong gen, uint flg, Kvp *kv, char *buf, int nbuf)
{
char *p;
@@ -512,12 +487,13 @@
{
assert(sz >= Treesz);
memset(t, 0, sizeof(Tree));
- t->nsucc = UNPACK32(p); p += 4;
+ t->nref = UNPACK32(p); p += 4;
t->nlbl = UNPACK32(p); p += 4;
t->ht = UNPACK32(p); p += 4;
t->flag = UNPACK32(p); p += 4;
t->gen = UNPACK64(p); p += 8;
- t->prev = UNPACK64(p); p += 8;
+ t->pred = UNPACK64(p); p += 8;
+ t->succ = UNPACK64(p); p += 8;
t->base = UNPACK64(p); p += 8;
t->bp.addr = UNPACK64(p); p += 8;
t->bp.hash = UNPACK64(p); p += 8;
@@ -530,12 +506,13 @@
packtree(char *p, int sz, Tree *t)
{
assert(sz >= Treesz);
- PACK32(p, t->nsucc); p += 4;
+ PACK32(p, t->nref); p += 4;
PACK32(p, t->nlbl); p += 4;
PACK32(p, t->ht); p += 4;
PACK32(p, t->flag); p += 4;
PACK64(p, t->gen); p += 8;
- PACK64(p, t->prev); p += 8;
+ PACK64(p, t->pred); p += 8;
+ PACK64(p, t->succ); p += 8;
PACK64(p, t->base); p += 8;
PACK64(p, t->bp.addr); p += 8;
PACK64(p, t->bp.hash); p += 8;
@@ -584,7 +561,7 @@
int i;
assert(sz == Blksz);
- memcpy(p, "gefs0007", 8); p += 8;
+ memcpy(p, "gefs0008", 8); p += 8;
PACK32(p, Blksz); p += 4;
PACK32(p, Bufspc); p += 4;
PACK32(p, fi->snap.ht); p += 4;
@@ -612,7 +589,7 @@
int i;
assert(sz == Blksz);
- if(memcmp(p, "gefs0007", 8) != 0){
+ if(memcmp(p, "gefs0008", 8) != 0){
werrstr("wrong block header %.8s\n", p);
return nil;
}
--- a/ream.c
+++ b/ream.c
@@ -117,11 +117,11 @@
kv.v = p;
memset(&t, 0, sizeof(Tree));
t.flag = Tforked;
- t.nsucc = 1;
+ t.nref = 1;
t.nlbl = 2;
t.ht = 1;
t.gen = fs->nextgen++;
- t.prev = -1ULL;
+ t.pred = -1ULL;
t.bp = r->bp;
p = packtree(p, e - p, &t);
kv.nv = p - kv.v;
@@ -136,11 +136,12 @@
kv.nk = p - kv.k;
kv.v = p;
memset(&t, 0, sizeof(Tree));
- t.nsucc = 0;
+ t.nref = 0;
t.nlbl = 1;
t.ht = 1;
t.gen = fs->nextgen++;
- t.prev = 0;
+ t.pred = 0;
+ t.succ = 2;
t.bp = a->bp;
p = packtree(p, e - p, &t);
kv.nv = p - kv.v;
@@ -155,11 +156,12 @@
kv.nk = p - kv.k;
kv.v = p;
memset(&t, 0, sizeof(Tree));
- t.nsucc = 0;
+ t.nref = 0;
t.nlbl = 1;
t.ht = 1;
t.gen = fs->nextgen++;
- t.prev = 0;
+ t.pred = 0;
+ t.succ = -1;
t.bp = r->bp;
p = packtree(p, e - p, &t);
kv.nv = p - kv.v;
--- a/snap.c
+++ b/snap.c
@@ -15,12 +15,10 @@
if(dl->ins == nil)
return nil;
- if(checkflag(dl->ins, Bdirty))
- enqueue(dl->ins);
+ if(!checkflag(dl->ins, Bdirty))
+ return nil;
- dl->hd = dl->ins->bp;
- if(dl->hd.addr == dl->tl.addr)
- dl->tl = dl->hd;
+ enqueue(dl->ins);
m.op = Oinsert;
dlist2kv(dl, &m, kvbuf, sizeof(kvbuf));
return btupsert(&fs->snap, &m, 1);
@@ -148,11 +146,19 @@
char*
freedl(Dlist *dl, int docontents)
{
+ char *e, buf[Kvmax];
Bptr bp, fb;
+ Msg m;
Blk *b;
char *p;
bp = dl->hd;
+ if(dl != &fs->snapdl){
+ m.op = Odelete;
+ dlist2kv(dl, &m, buf, sizeof(buf));
+ if((e = btupsert(&fs->snap, &m, 1)) != nil)
+ return e;
+ }
while(bp.addr != -1){
if((b = getblk(bp, 0)) == nil)
return Efs;
@@ -172,90 +178,55 @@
}
static char*
-mergedl(vlong succ, vlong gen, vlong bgen)
+mergedl(vlong merge, vlong gen, vlong bgen)
{
- char *err, buf[2][Kvmax];
+ char *e, buf[2][Kvmax];
Dlist *d, *m;
Msg msg[2];
Blk *b;
-// vlong x;
- err = nil;
- d = getdl(gen, bgen);
- m = getdl(succ, bgen);
- if(d == nil || m == nil){
- err = Efs;
- goto Out;
- }
- if(m->ins == nil){
- m->hd = d->hd;
- m->tl = d->tl;
- m->ins = d->ins;
+ if((d = getdl(merge, bgen)) == nil)
+ return Enomem;
+ if((m = getdl(gen, bgen)) == nil)
+ return Enomem;
+ /*
+ * If the dest dlist didn't exist,
+ * just move the merge dlist over
+ * and be done with it, otherwise
+ * chain onto the existing dlist
+ * tail.
+ */
+ if(d->hd.addr == -1){
+ assert(d->ins == nil);
+ d->hd = m->hd;
+ d->tl = m->tl;
+ d->ins = m->ins;
+ if(d->ins != nil)
+ holdblk(d->ins);
}else{
- m->hd = d->hd;
- if((b = getblk(d->tl, 0)) == nil)
- goto Out;
- msg[0].op = Odelete;
- dlist2kv(d, &msg[0], buf[0], sizeof(buf[0]));
- msg[1].op = Oinsert;
- dlist2kv(m, &msg[1], buf[1], sizeof(buf[1]));
- if((err = btupsert(&fs->snap, msg, 2)) != nil)
- sysfatal("merge deadlists: %s", err);
-
- packbp(b->buf+2, Blksz, &m->hd);
+ if(m->ins != nil && checkflag(m->ins, Bdirty))
+ enqueue(m->ins);
+ if(d->tl.addr == d->ins->bp.addr)
+ b = holdblk(d->ins);
+ else
+ b = getblk(d->tl, 0);
+ if(b == nil)
+ return Efs;
+ b->logp = m->hd;
+ setflag(b, Bdirty);
enqueue(b);
dropblk(b);
-
-// TODO: merge
-// if(m->ins->logsz + d->ins->logsz < Dlspc){
-// p = d->ins->data;
-// q = m->ins->data + m->ins->logsz;
-// for(i = 0; i < d->ins->logsz; i += 8){
-// m->ins->logsz += 8;
-// x = UNPACK64(p);
-// PACK64(q, x);
-// p += 8;
-// q += 8;
-// }
-// }
}
-Out:
- if(d != nil)
- putdl(d);
- if(m != nil)
- putdl(m);
- return err;
+ msg[0].op = Odelete;
+ dlist2kv(m, &msg[0], buf[0], sizeof(buf[0]));
+ msg[1].op = Oinsert;
+ dlist2kv(d, &msg[1], buf[1], sizeof(buf[1]));
+ e = btupsert(&fs->snap, msg, 2);
+ putdl(m);
+ putdl(d);
+ return e;
}
-vlong
-successor(vlong gen)
-{
- char *e, pfx[9];
- vlong id, succ;
- Scan s;
-
- pfx[0] = Kslink;
- succ = -1;
- PACK64(pfx+1, gen);
- btnewscan(&s, pfx, sizeof(pfx));
- if((e = btenter(&fs->snap, &s)) != nil)
- goto Err;
- if((e = btnext(&s, &s.kv)) != nil)
- goto Err;
- if(!s.done)
- kv2link(&s.kv, &id, &succ);
- if((e = btnext(&s, &s.kv)) != nil)
- goto Err;
- if(!s.done)
- sysfatal("multiple successors in cleanup");
- btexit(&s);
- return succ;
-Err:
- fprint(2, "error getting snap successor: %s", e);
- btexit(&s);
- return -1;
-}
-
static char*
reclaimblocks(vlong gen, vlong succ, vlong prev)
{
@@ -262,7 +233,6 @@
char *e, pfx[9];
Dlist dl;
Scan s;
- Msg m;
pfx[0] = Kdlist;
PACK64(pfx+1, gen);
@@ -276,18 +246,12 @@
break;
kv2dlist(&s.kv, &dl);
- /*
- * delete the dlist before processing it; it's
- * better to leak blocks than to double free.
- */
- m.op = Odelete;
- m.Kvp = s.kv;
- if((e = btupsert(&fs->snap, &m, 1)) != nil)
- break;
- if(succ == -1 && dl.bgen > prev)
- e = freedl(&dl, 1);
- else
+ if(succ != -1 && dl.bgen <= prev)
e = mergedl(succ, dl.gen, dl.bgen);
+ else if(dl.bgen <= prev)
+ e = mergedl(prev, dl.gen, dl.bgen);
+ else
+ e = freedl(&dl, 1);
if(e != nil)
break;
}
@@ -328,7 +292,7 @@
nm++;
}
- if(t->nlbl == 0 && t->nsucc <= 1){
+ if(t->nlbl == 0 && t->nref <= 1){
m[nm].op = Odelete;
m[nm].k = buf[nm];
if((e = packsnap(buf[nm], sizeof(buf[nm]), t->gen)) == nil)
@@ -346,7 +310,7 @@
return e;
if((e = btupsert(&fs->snap, m, nm)) != nil)
return e;
- if((e = reclaimblocks(t->gen, succ, t->prev)) != nil)
+ if((e = reclaimblocks(t->gen, succ, t->pred)) != nil)
return e;
return nil;
}
@@ -376,28 +340,32 @@
n->memref = 1;
n->dirty = 0;
n->nlbl = 1;
- n->nsucc = 0;
+ n->nref = 0;
n->ht = t->ht;
n->bp = t->bp;
- n->prev = t->prev;
+ n->pred = t->pred;
+ n->succ = -1;
n->base = t->gen;
n->gen = aincv(&fs->nextgen, 1);
n->memgen = aincv(&fs->nextgen, 1);
m[i].op = Oretag;
- retag2kv(t->gen, 0, 1, &m[i], buf[i], sizeof(buf[i]));
+ retag2kv(t->gen, t->pred, t->succ, 0, 1, &m[i], buf[i], sizeof(buf[i]));
i++;
m[i].op = Oinsert;
lbl2kv(name, n->gen, 1, &m[i], buf[i], sizeof(buf[i]));
i++;
+ m[i].op = Oinsert;
+ tree2kv(n, &m[i], buf[i], sizeof(buf[i]));
+ i++;
}else{
t->nlbl++;
m[i].op = Oretag;
- retag2kv(t->gen, 1, 0, &m[i], buf[i], sizeof(buf[i]));
+ retag2kv(t->gen, t->pred, t->succ, 1, 0, &m[i], buf[i], sizeof(buf[i]));
i++;
m[i].op = Oinsert;
- t->prev = t->gen;
+ t->pred = t->gen;
t->nlbl++;
lbl2kv(name, t->gen, 0, &m[i], buf[i], sizeof(buf[i]));
i++;
@@ -425,7 +393,7 @@
/* update the old kvp */
o->nlbl--;
- o->nsucc++;
+ o->nref++;
/* create the new one */
@@ -435,20 +403,20 @@
t->dirty = 0;
t->nlbl = 1;
- t->nsucc = 0;
+ t->nref = 0;
t->ht = o->ht;
t->bp = o->bp;
t->base = o->base;
- if(o->nlbl == 0 && o->nsucc == 1)
- t->prev = o->prev;
+ if(o->nlbl == 0 && o->nref == 1)
+ t->pred = o->pred;
else
- t->prev = o->gen;
+ t->pred = o->gen;
t->gen = o->memgen;
t->memgen = aincv(&fs->nextgen, 1);
i = 0;
m[i].op = Oretag;
- retag2kv(o->gen, -1, 1, &m[i], buf[i], sizeof(buf[i]));
+ retag2kv(o->gen, o->pred, t->gen, -1, 1, &m[i], buf[i], sizeof(buf[i]));
i++;
m[i].op = Oinsert;
@@ -456,10 +424,6 @@
i++;
m[i].op = Oinsert;
- link2kv(t->prev, t->gen, &m[i], buf[i], sizeof(buf[i]));
- i++;
-
- m[i].op = Oinsert;
lbl2kv(lbl, t->gen, Lmut, &m[i], buf[i], sizeof(buf[i]));
i++;
@@ -472,7 +436,7 @@
o->dirty = 0;
/* this was the last ref to the snap */
- if(o->nlbl == 0 && o->nsucc == 1)
+ if(o->nlbl == 0 && o->nref == 1)
delsnap(o, -1, nil);
closesnap(o);
asetp(r, t);
@@ -595,23 +559,18 @@
putdl(dl);
return -1;
}
- if(dl->ins != nil){
+ if(dl->ins != nil)
enqueue(dl->ins);
- /* enqueuing updates the hashes */
- if(dl->ins->bp.addr == dl->tl.addr)
- dl->tl = dl->ins->bp;
- b->logp = dl->ins->bp;
- }else{
+ if(dl->tl.addr == -1)
dl->tl = b->bp;
- b->logp = (Bptr){-1, -1, -1};
- }
- cacheins(b);
+ b->logp = dl->hd;
dl->hd = b->bp;
dl->ins = b;
+ cacheins(b);
}
p = dl->ins->data + dl->ins->logsz;
- dl->ins->flag |= Bdirty;
dl->ins->logsz += 8;
+ setflag(dl->ins, Bdirty);
PACK64(p, bp.addr);
if(t != &fs->snap)
putdl(dl);
--- a/tree.c
+++ b/tree.c
@@ -400,7 +400,9 @@
static int
apply(Kvp *kv, Msg *m, char *buf, int nbuf)
{
+ char *p;
Tree t;
+ vlong v;
switch(m->op){
case Oclearb:
@@ -416,10 +418,13 @@
statupdate(kv, m);
return 1;
case Oretag:
- assert(m->nv == 2);
unpacktree(&t, kv->v, kv->nv);
- t.nlbl += m->v[0];
- t.nsucc += m->v[1];
+ p = m->v;
+ t.pred = UNPACK64(p); p += 8;
+ t.succ = UNPACK64(p); p += 8;
+ t.nlbl += *p; p++;
+ t.nref += *p; p++;
+ assert(p == m->v + m->nv);
packtree(kv->v, kv->nv, &t);
return 1;
default: