From 255adc515aeab4bd870e548bb4154c2682871c05 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 3 Jun 2020 23:46:15 -0400 Subject: [PATCH] bcachefs: Always increment bucket gen on bucket reuse Not doing so confuses copygc Signed-off-by: Kent Overstreet Signed-off-by: Kent Overstreet --- fs/bcachefs/alloc_background.c | 38 +++++++++++++++++++++++++--------- fs/bcachefs/buckets.c | 30 +++++++++++++++++---------- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c index 30541c8fe3b0e..44ad9821c8073 100644 --- a/fs/bcachefs/alloc_background.c +++ b/fs/bcachefs/alloc_background.c @@ -860,12 +860,22 @@ static int bch2_invalidate_one_bucket2(struct btree_trans *trans, g = bucket(ca, b); m = READ_ONCE(g->mark); - bch2_mark_alloc_bucket(c, ca, b, true, gc_pos_alloc(c, NULL), 0); + invalidating_cached_data = m.cached_sectors != 0; + + /* + * If we're not invalidating cached data, we only increment the bucket + * gen in memory here, the incremented gen will be updated in the btree + * by bch2_trans_mark_pointer(): + */ + + if (!invalidating_cached_data) + bch2_invalidate_bucket(c, ca, b, &m); + else + bch2_mark_alloc_bucket(c, ca, b, true, gc_pos_alloc(c, NULL), 0); spin_unlock(&c->freelist_lock); percpu_up_read(&c->mark_lock); - invalidating_cached_data = m.cached_sectors != 0; if (!invalidating_cached_data) goto out; @@ -887,18 +897,26 @@ retry: if (ret) return ret; - /* - * The allocator has to start before journal replay is finished - thus, - * we have to trust the in memory bucket @m, not the version in the - * btree: - */ percpu_down_read(&c->mark_lock); - g = bucket(ca, b); + g = bucket(ca, iter->pos.offset); m = READ_ONCE(g->mark); - u = alloc_mem_to_key(g, m); + + if (unlikely(!test_bit(BCH_FS_ALLOC_WRITTEN, &c->flags))) { + /* + * 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: + */ + u = alloc_mem_to_key(g, m); + } else { + u = bch2_alloc_unpack(k); + u.read_time = g->io_time[READ]; + u.write_time = g->io_time[WRITE]; + } + percpu_up_read(&c->mark_lock); - invalidating_cached_data = m.cached_sectors != 0; + invalidating_cached_data = u.cached_sectors != 0; u.gen++; u.data_type = 0; diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c index 4074bc073cfe1..08e8b578fff5a 100644 --- a/fs/bcachefs/buckets.c +++ b/fs/bcachefs/buckets.c @@ -1496,6 +1496,8 @@ static int bch2_trans_mark_pointer(struct btree_trans *trans, struct bkey_s_c k_a; struct bkey_alloc_unpacked u; struct bkey_i_alloc *a; + struct bucket *g; + struct bucket_mark m; int ret; ret = trans_get_key(trans, BTREE_ID_ALLOC, @@ -1504,26 +1506,32 @@ static int bch2_trans_mark_pointer(struct btree_trans *trans, if (ret < 0) return ret; - if (k_a.k->type != KEY_TYPE_alloc || - (!ret && unlikely(!test_bit(BCH_FS_ALLOC_WRITTEN, &c->flags)))) { + percpu_down_read(&c->mark_lock); + g = bucket(ca, iter->pos.offset); + m = READ_ONCE(g->mark); + + if (unlikely(!test_bit(BCH_FS_ALLOC_WRITTEN, &c->flags) && !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 - unless we're already * updating that key: */ - struct bucket *g; - struct bucket_mark m; - - 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); + u = alloc_mem_to_key(g, m); } else { - u = bch2_alloc_unpack(k_a); + u = bch2_alloc_unpack(k_a); + u.read_time = g->io_time[READ]; + u.write_time = g->io_time[WRITE]; } + percpu_up_read(&c->mark_lock); + + /* + * Incrementing the bucket gen can be done lazily: + */ + if (gen_after(m.gen, u.gen) && !u.data_type) + u.gen = m.gen; + ret = __mark_pointer(c, k, p, sectors, data_type, u.gen, &u.data_type, &u.dirty_sectors, &u.cached_sectors); if (ret) -- 2.30.2