ref: d8f3576e5dc6793b98314f202cfba0c65bfbee12
parent: 93b53d81984032ba86acff73c220c59c40fe9ffe
author: Ori Bernstein <[email protected]>
date: Sun Oct 3 23:38:42 EDT 2021
tree: refcount blocks correctly
--- a/blk.c
+++ b/blk.c
@@ -14,7 +14,7 @@
};
static vlong blkalloc_lk(Arena*);
-static int blkdealloc(vlong);
+static int blkdealloc_lk(vlong);
static void cachedel(vlong);
static Blk *cacheblk(Blk*);
static Blk *lookupblk(vlong);
@@ -44,6 +44,7 @@
b->bp.addr = bp;
b->bp.hash = -1;
b->bp.gen = -1;
+ b->ref = 0; /* caller must increment */
b->cnext = nil;
b->cprev = nil;
b->hnext = nil;
@@ -263,6 +264,7 @@
Nextblk:
if((b = readblk(bp, 0)) == nil)
return -1;
+ cacheblk(b);
p = b->data;
bh = GBIT64(p + 0);
/* the hash covers the log and offset */
@@ -438,8 +440,12 @@
break;
}
}
- if(blkdealloc(bp) == -1)
+ lock(a);
+ if(blkdealloc_lk(bp) == -1){
+ unlock(a);
return -1;
+ }
+ unlock(a);
}
}
finalize(a->logtl);
@@ -484,7 +490,7 @@
}
static int
-blkdealloc(vlong b)
+blkdealloc_lk(vlong b)
{
Arena *a;
int r;
@@ -491,7 +497,6 @@
r = -1;
a = getarena(b);
- lock(a);
cachedel(b);
if(freerange(a->free, b, Blksz) == -1)
goto out;
@@ -499,7 +504,6 @@
goto out;
r = 0;
out:
- unlock(a);
return r;
}
@@ -559,7 +563,7 @@
b->bp.addr = bp;
b->bp.hash = -1;
b->bp.gen = fs->nextgen;
- b->ref = 1;
+ b->ref = 0; /* cacheblk incremnets */
b->data = b->buf + Hdrsz;
return cacheblk(b);
}
@@ -578,8 +582,6 @@
for(b = bkt->b; b != nil; b = b->hnext)
if(b->bp.addr == off)
break;
- if(b != nil)
- pinblk(b);
unlock(bkt);
return b;
}
@@ -592,19 +594,19 @@
u32int h;
/* FIXME: better hash. */
+ refblk(b);
assert(b->bp.addr != 0);
+ assert(!(b->flag & Bzombie));
h = ihash(b->bp.addr);
- ainc(&b->ref);
bkt = &fs->cache[h % fs->cmax];
lock(bkt);
for(e = bkt->b; e != nil; e = e->hnext){
if(b == e)
- goto found;
+ goto Found;
assert(b->bp.addr != e->bp.addr);
}
bkt->b = b;
-found:
- ainc(&b->ref);
+Found:
unlock(bkt);
lock(&fs->lrulk);
@@ -626,10 +628,10 @@
b->cnext = fs->chead;
b->cprev = nil;
fs->chead = b;
- if((b->flag&Bcache) == 0){
- b->flag |= Bcache;
+ if((b->flag&Bcached) == 0){
+ b->flag |= Bcached;
fs->ccount++;
- ainc(&b->ref);
+ refblk(b);
}
c=0;
USED(c);
@@ -794,7 +796,7 @@
}
Blk*
-pinblk(Blk *b)
+refblk(Blk *b)
{
ainc(&b->ref);
return b;
@@ -820,9 +822,13 @@
{
if(b == nil)
return;
+ assert(b->ref > 0);
+ if(b->flag & Bzombie)
+ fprint(2, "reaping zombie: %B @ %ld\n", b->bp, b->ref);
if(adec(&b->ref) == 0){
assert((b->flag & Bqueued) || !(b->flag & Bdirty));
cachedel(b->bp.addr);
+ assert(lookupblk(b->bp.addr) == nil);
free(b);
}
}
@@ -832,13 +838,22 @@
{
Arena *a;
- assert(b->ref == 1 && b->flag & (Bdirty|Bqueued) == Bdirty);
+ /* we can have patterns like:
+ * b = getblk();
+ * use(b);
+ * freeblk(b);
+ * unref(b);
+ */
+ if(b->ref != 1 && ((b->flag & Bcached) && b->ref != 2)){
+ fprint(2, "warning: dangling refs: %B @ %ld\n", b->bp, b->ref);
+ b->flag |= Bzombie;
+ }
+ assert((b->flag & Bqueued) == 0);
a = getarena(b->bp.addr);
lock(a);
logop(a, b->bp.addr, LogFree);
- blkdealloc(b->bp.addr);
+ blkdealloc_lk(b->bp.addr);
unlock(a);
- free(b);
}
int
--- a/check.c
+++ b/check.c
@@ -72,6 +72,7 @@
}
if(badblk(c, h - 1, &x, &y))
fail++;
+ putblk(c);
}
r = keycmp(&x, &y);
switch(r){
@@ -188,11 +189,14 @@
void
fshowfs(int fd, char *m)
{
+ Blk *b;
int h;
fprint(fd, "=== %s\n", m);
fprint(fd, "\tht: %d\n", fs->root.ht);
- rshowblk(fd, getroot(&fs->root, &h), 0, 1);
+ b = getroot(&fs->root, &h);
+ rshowblk(fd, b, 0, 1);
+ putblk(b);
}
void
--- a/dat.h
+++ b/dat.h
@@ -64,7 +64,6 @@
* ptr: off[8] hash[8] -- a key for an Dir block.
* dir: fixed statbuf header, user ids
*/
- Kref, /* off[8] => ptr[16]: pointer to refcount page */
Kdat, /* qid[8] off[8] => ptr[16]: pointer to data page */
Kent, /* pqid[8] name[n] => dir[n]: serialized Dir */
Ksnap, /* name[n] => dent[16] ptr[16]: snapshot root */
@@ -75,7 +74,8 @@
Bdirty = 1 << 0,
Bqueued = 1 << 1,
Bfinal = 1 << 2,
- Bcache = 1 << 3,
+ Bcached = 1 << 3,
+ Bzombie = 1 << 4,
};
#define Efs "i will not buy this fs, it is scratched"
--- a/fns.h
+++ b/fns.h
@@ -13,7 +13,7 @@
Blk* shadow(Blk*, Path*, Path*);
Blk* getroot(Tree*, int*);
Blk* getblk(Bptr, int);
-Blk* pinblk(Blk*);
+Blk* refblk(Blk*);
Blk* readblk(vlong, int);
Arena* getarena(vlong);
void putblk(Blk*);
--- a/fs.c
+++ b/fs.c
@@ -49,11 +49,13 @@
b = getblk(f->root.bp, 0);
if(b == nil)
return Efs;
+
if(lk)
rlock(f->dent);
e = btlookupat(b, k, kv, bp);
if(lk)
runlock(f->dent);
+ putblk(b);
return e;
}
@@ -552,6 +554,14 @@
rerror(m, "no such fid");
return;
}
+
+ lock(f);
+ if(f->scan != nil){
+ btdone(f->scan);
+ f->scan = nil;
+ }
+ unlock(f);
+
clunkfid(f);
r.type = Rclunk;
respond(m, &r);
--- a/ream.c
+++ b/ream.c
@@ -128,6 +128,7 @@
s->type = Tsuper;
s->bp.addr = sz;
s->data = s->buf + Hdrsz;
+ s->ref = 1;
fillsuper(s);
finalize(s);
syncblk(s);
--- a/tree.c
+++ b/tree.c
@@ -461,6 +461,7 @@
}
b->nbuf = j;
}
+ freeblk(b);
p->n = n;
return 0;
}
@@ -552,6 +553,7 @@
setmsg(r, j, &m);
}
}
+ freeblk(b);
p->split = 1;
p->l = l;
p->r = r;
@@ -640,6 +642,8 @@
setmsg(d, o++, &m);
}
}
+ freeblk(a);
+ freeblk(b);
//showfs("postmerge");
enqueue(d);
p->merge = 1;
@@ -756,6 +760,8 @@
setmsg(d, o++, &m);
}
}
+ freeblk(a);
+ freeblk(b);
enqueue(l);
enqueue(r);
p->merge = 1;
@@ -806,7 +812,7 @@
if(p->idx == -1)
return 0;
if(pp != nil){
- if((m = pp->n) == nil)
+ if((m = refblk(pp->n)) == nil)
return 0;
}else{
if((m = getblk(km.bp, 0)) == nil)
@@ -838,6 +844,7 @@
done:
ret = 0;
out:
+ putblk(m);
putblk(l);
putblk(r);
if(pp == nil)
@@ -982,18 +989,12 @@
Path *p;
for(p = path; p != path + npath; p++){
- if(p->b != nil)
- putblk(p->b);
- if(p->n != nil)
- putblk(p->n);
- if(p->l != nil)
- putblk(p->l);
- if(p->r != nil)
- putblk(p->r);
- if(p->nl != nil)
- putblk(p->nl);
- if(p->nr != nil)
- putblk(p->nr);
+ putblk(p->b);
+ putblk(p->n);
+ putblk(p->l);
+ putblk(p->r);
+ putblk(p->nl);
+ putblk(p->nr);
}
}
@@ -1143,7 +1144,7 @@
*h = t->ht;
unlock(&t->lk);
- return getblk(t->bp, 0);
+ return getblk(bp, 0);
}
static char*
@@ -1182,12 +1183,13 @@
char*
btlookupat(Blk *b0, Key *k, Kvp *r, Blk **bp)
{
- int idx, same, done;
+ int idx, same, done, r0;
char *ret;
- Blk *b;
+ Blk *b, *c;
*bp = nil;
- b = pinblk(b0);
+ r0 = b0->ref;
+ b = refblk(b0);
assert(k != r);
while(b->type == Tpivot){
ret = collect(b, k, r, &done);
@@ -1194,18 +1196,24 @@
if(done)
return ret;
idx = blksearch(b, k, r, nil);
- if(idx == -1)
+ if(idx == -1){
+ assert(b0->ref == r0 + (b == b0) ? 1 : 0);
+ putblk(b);
return Eexist;
- putblk(b);
- if((b = getblk(r->bp, 0)) == nil)
+ }
+ if((c = getblk(r->bp, 0)) == nil)
return Efs;
+ putblk(b);
+ b = c;
}
assert(b->type == Tleaf);
blksearch(b, k, r, &same);
if(!same){
+ assert(b0->ref == r0 + (b == b0) ? 1 : 0);
putblk(b);
return Eexist;
}
+ assert(b0->ref == r0 + (b == b0) ? 1 : 0);
*bp = b;
return nil;
}
@@ -1287,6 +1295,7 @@
case Oinsert:
s->present = 1;
kv2dir(m, d);
+ fprint(2, "name: %s\n", d->name);
break;
case Odelete:
s->present = 0;
@@ -1349,8 +1358,10 @@
}
start = i;
p[i-1].vi++;
+ putblk(p[i].b);
p[i].vi = 0;
p[i].bi = 0;
+ p[i].b = nil;
}
for(i = start; i < h; i++){
getval(p[i-1].b, p[i-1].vi, &kv);
@@ -1402,8 +1413,7 @@
int i;
for(i = 0; i < s->root.ht; i++)
- if(s->path[i].b != nil)
- putblk(s->path[i].b);
+ putblk(s->path[i].b);
free(s->path);
}