summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2019-08-27 17:34:03 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2019-08-28 00:38:06 -0400
commitbc3a6a71a37c63a0f970062dd97ea61ecd12bf90 (patch)
tree2accfc39e7e87956cb91a6dfb891d1ff4737202e
parent14f68409bec43faff9d7480632488def385e0638 (diff)
bcachefs: Trust in memory bucket mark
This fixes a bug in the journal replay -> extent_replay_key -> split_compressed path, when we do an update that changes alloc info but the alloc info in the btree isn't up to date yet. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/alloc_background.c14
-rw-r--r--fs/bcachefs/alloc_background.h14
-rw-r--r--fs/bcachefs/buckets.c43
3 files changed, 45 insertions, 26 deletions
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c
index 4cf728cea393..8b06f51da05b 100644
--- a/fs/bcachefs/alloc_background.c
+++ b/fs/bcachefs/alloc_background.c
@@ -205,20 +205,6 @@ void bch2_alloc_to_text(struct printbuf *out, struct bch_fs *c,
get_alloc_field(a.v, &d, i));
}
-static inline struct bkey_alloc_unpacked
-alloc_mem_to_key(struct bucket *g, struct bucket_mark m)
-{
- return (struct bkey_alloc_unpacked) {
- .gen = m.gen,
- .oldest_gen = g->oldest_gen,
- .data_type = m.data_type,
- .dirty_sectors = m.dirty_sectors,
- .cached_sectors = m.cached_sectors,
- .read_time = g->io_time[READ],
- .write_time = g->io_time[WRITE],
- };
-}
-
int bch2_alloc_read(struct bch_fs *c, struct journal_keys *journal_keys)
{
struct btree_trans trans;
diff --git a/fs/bcachefs/alloc_background.h b/fs/bcachefs/alloc_background.h
index 0c1a0f0dd2ab..134c6d81397c 100644
--- a/fs/bcachefs/alloc_background.h
+++ b/fs/bcachefs/alloc_background.h
@@ -17,6 +17,20 @@ struct bkey_alloc_unpacked bch2_alloc_unpack(struct bkey_s_c);
void bch2_alloc_pack(struct bkey_i_alloc *,
const struct bkey_alloc_unpacked);
+static inline struct bkey_alloc_unpacked
+alloc_mem_to_key(struct bucket *g, struct bucket_mark m)
+{
+ return (struct bkey_alloc_unpacked) {
+ .gen = m.gen,
+ .oldest_gen = g->oldest_gen,
+ .data_type = m.data_type,
+ .dirty_sectors = m.dirty_sectors,
+ .cached_sectors = m.cached_sectors,
+ .read_time = g->io_time[READ],
+ .write_time = g->io_time[WRITE],
+ };
+}
+
#define ALLOC_SCAN_BATCH(ca) max_t(size_t, 1, (ca)->mi.nbuckets >> 9)
const char *bch2_alloc_invalid(const struct bch_fs *, struct bkey_s_c);
diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c
index 2bcf929a6d0d..ea7f3e926603 100644
--- a/fs/bcachefs/buckets.c
+++ b/fs/bcachefs/buckets.c
@@ -1361,7 +1361,7 @@ static int trans_get_key(struct btree_trans *trans,
: !bkey_cmp(pos, i->iter->pos))) {
*iter = i->iter;
*k = bkey_i_to_s_c(i->k);
- return 0;
+ return 1;
}
*iter = __bch2_trans_get_iter(trans, btree_id, pos,
@@ -1424,18 +1424,37 @@ static int bch2_trans_mark_pointer(struct btree_trans *trans,
ret = trans_get_key(trans, BTREE_ID_ALLOC,
POS(p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr)),
&iter, &k);
- if (ret)
+ if (ret < 0)
return ret;
- if (k.k->type != KEY_TYPE_alloc) {
- bch_err_ratelimited(c, "pointer to nonexistent bucket %u:%zu",
- p.ptr.dev,
- PTR_BUCKET_NR(ca, &p.ptr));
- ret = -1;
- goto out;
- }
+ if (!ret) {
+ /*
+ * During journal replay, and if gc repairs alloc info at
+ * runtime, the alloc info in the btree might not be up to date
+ * yet - so, trust the in memory mark:
+ */
+ struct bucket *g;
+ struct bucket_mark m;
- u = bch2_alloc_unpack(k);
+ percpu_down_read(&c->mark_lock);
+ g = bucket(ca, iter->pos.offset);
+ m = READ_ONCE(g->mark);
+ u = alloc_mem_to_key(g, m);
+ percpu_up_read(&c->mark_lock);
+ } else {
+ /*
+ * Unless we're already updating that key:
+ */
+ if (k.k->type != KEY_TYPE_alloc) {
+ bch_err_ratelimited(c, "pointer to nonexistent bucket %u:%zu",
+ p.ptr.dev,
+ PTR_BUCKET_NR(ca, &p.ptr));
+ ret = -1;
+ goto out;
+ }
+
+ u = bch2_alloc_unpack(k);
+ }
if (gen_after(u.gen, p.ptr.gen)) {
ret = 1;
@@ -1484,7 +1503,7 @@ static int bch2_trans_mark_stripe_ptr(struct btree_trans *trans,
int ret = 0;
ret = trans_get_key(trans, BTREE_ID_EC, POS(0, p.idx), &iter, &k);
- if (ret)
+ if (ret < 0)
return ret;
if (k.k->type != KEY_TYPE_stripe) {
@@ -1599,7 +1618,7 @@ static int __bch2_trans_mark_reflink_p(struct btree_trans *trans,
ret = trans_get_key(trans, BTREE_ID_REFLINK,
POS(0, idx), &iter, &k);
- if (ret)
+ if (ret < 0)
return ret;
if (k.k->type != KEY_TYPE_reflink_v) {