diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c index 22aa845ea630..3775b65a89a6 100644 --- a/fs/bcachefs/btree_gc.c +++ b/fs/bcachefs/btree_gc.c @@ -887,6 +887,82 @@ int bch2_gc(struct bch_fs *c, struct journal_keys *journal_keys, return ret; } +/* + * For recalculating oldest gen, we only need to walk keys in leaf nodes; btree + * node pointers currently never have cached pointers that can become stale: + */ +static int bch2_gc_btree_gens(struct bch_fs *c, enum btree_id id) +{ + struct btree_trans trans; + struct btree_iter *iter; + struct bkey_s_c k; + int ret; + + bch2_trans_init(&trans, c, 0, 0); + + for_each_btree_key(&trans, iter, id, POS_MIN, BTREE_ITER_PREFETCH, k, ret) { + struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k); + const struct bch_extent_ptr *ptr; + + percpu_down_read(&c->mark_lock); + bkey_for_each_ptr(ptrs, ptr) { + struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev); + struct bucket *g = PTR_BUCKET(ca, ptr, false); + + if (gen_after(g->gc_gen, ptr->gen)) + g->gc_gen = ptr->gen; + + if (gen_after(g->mark.gen, ptr->gen) > 32) { + /* rewrite btree node */ + + } + } + percpu_up_read(&c->mark_lock); + } + + bch2_trans_exit(&trans); + return ret; +} + +int bch2_gc_gens(struct bch_fs *c) +{ + struct bch_dev *ca; + struct bucket_array *buckets; + struct bucket *g; + unsigned i; + int ret; + + down_read(&c->state_lock); + + for_each_member_device(ca, c, i) { + down_read(&ca->bucket_lock); + buckets = bucket_array(ca); + + for_each_bucket(g, buckets) + g->gc_gen = g->mark.gen; + up_read(&ca->bucket_lock); + } + + for (i = 0; i < BTREE_ID_NR; i++) + if (btree_node_type_needs_gc(i)) { + ret = bch2_gc_btree_gens(c, i); + if (ret) + goto err; + } + + for_each_member_device(ca, c, i) { + down_read(&ca->bucket_lock); + buckets = bucket_array(ca); + + for_each_bucket(g, buckets) + g->oldest_gen = g->gc_gen; + up_read(&ca->bucket_lock); + } +err: + up_read(&c->state_lock); + return ret; +} + /* Btree coalescing */ static void recalc_packed_keys(struct btree *b) @@ -1262,7 +1338,14 @@ static int bch2_gc_thread(void *arg) last = atomic_long_read(&clock->now); last_kick = atomic_read(&c->kick_gc); + /* + * Full gc is currently incompatible with btree key cache: + */ +#if 0 ret = bch2_gc(c, NULL, false, false); +#else + ret = bch2_gc_gens(c); +#endif if (ret) bch_err(c, "btree gc failed: %i", ret); diff --git a/fs/bcachefs/btree_gc.h b/fs/bcachefs/btree_gc.h index 3966d5e54cfd..3694a3df62a8 100644 --- a/fs/bcachefs/btree_gc.h +++ b/fs/bcachefs/btree_gc.h @@ -8,6 +8,7 @@ void bch2_coalesce(struct bch_fs *); struct journal_keys; int bch2_gc(struct bch_fs *, struct journal_keys *, bool, bool); +int bch2_gc_gens(struct bch_fs *); void bch2_gc_thread_stop(struct bch_fs *); int bch2_gc_thread_start(struct bch_fs *); void bch2_mark_dev_superblock(struct bch_fs *, struct bch_dev *, unsigned); diff --git a/fs/bcachefs/buckets_types.h b/fs/bcachefs/buckets_types.h index 070e10dfa7bb..172b0ccf2b4f 100644 --- a/fs/bcachefs/buckets_types.h +++ b/fs/bcachefs/buckets_types.h @@ -39,6 +39,7 @@ struct bucket { u16 io_time[2]; u8 oldest_gen; + u8 gc_gen; unsigned gen_valid:1; }; diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c index 663b59e78824..1800e0f7f81e 100644 --- a/fs/bcachefs/sysfs.c +++ b/fs/bcachefs/sysfs.c @@ -486,9 +486,16 @@ STORE(bch2_fs) bch2_coalesce(c); if (attr == &sysfs_trigger_gc) { + /* + * Full gc is currently incompatible with btree key cache: + */ +#if 0 down_read(&c->state_lock); bch2_gc(c, NULL, false, false); up_read(&c->state_lock); +#else + bch2_gc_gens(c); +#endif } if (attr == &sysfs_trigger_alloc_write) {