Commit 91ddd715 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: split up btree cache counters for live, freeable

this is prep for introducing a second live list and shrinker for pinned
nodes
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 691f2cba
...@@ -49,7 +49,7 @@ void bch2_recalc_btree_reserve(struct bch_fs *c) ...@@ -49,7 +49,7 @@ void bch2_recalc_btree_reserve(struct bch_fs *c)
static inline size_t btree_cache_can_free(struct btree_cache *bc) static inline size_t btree_cache_can_free(struct btree_cache *bc)
{ {
return max_t(int, 0, bc->nr_used - bc->nr_reserve); return max_t(int, 0, bc->nr_live + bc->nr_freeable - bc->nr_reserve);
} }
static void btree_node_to_freedlist(struct btree_cache *bc, struct btree *b) static void btree_node_to_freedlist(struct btree_cache *bc, struct btree *b)
...@@ -64,6 +64,8 @@ static void btree_node_data_free(struct bch_fs *c, struct btree *b) ...@@ -64,6 +64,8 @@ static void btree_node_data_free(struct bch_fs *c, struct btree *b)
{ {
struct btree_cache *bc = &c->btree_cache; struct btree_cache *bc = &c->btree_cache;
BUG_ON(btree_node_hashed(b));
/* /*
* This should really be done in slub/vmalloc, but we're using the * This should really be done in slub/vmalloc, but we're using the
* kmalloc_large() path, so we're working around a slub bug by doing * kmalloc_large() path, so we're working around a slub bug by doing
...@@ -87,7 +89,7 @@ static void btree_node_data_free(struct bch_fs *c, struct btree *b) ...@@ -87,7 +89,7 @@ static void btree_node_data_free(struct bch_fs *c, struct btree *b)
#endif #endif
b->aux_data = NULL; b->aux_data = NULL;
bc->nr_used--; bc->nr_freeable--;
btree_node_to_freedlist(bc, b); btree_node_to_freedlist(bc, b);
} }
...@@ -167,7 +169,7 @@ struct btree *__bch2_btree_node_mem_alloc(struct bch_fs *c) ...@@ -167,7 +169,7 @@ struct btree *__bch2_btree_node_mem_alloc(struct bch_fs *c)
bch2_btree_lock_init(&b->c, 0); bch2_btree_lock_init(&b->c, 0);
bc->nr_used++; bc->nr_freeable++;
list_add(&b->list, &bc->freeable); list_add(&b->list, &bc->freeable);
return b; return b;
} }
...@@ -186,6 +188,7 @@ void bch2_btree_node_to_freelist(struct bch_fs *c, struct btree *b) ...@@ -186,6 +188,7 @@ void bch2_btree_node_to_freelist(struct bch_fs *c, struct btree *b)
void bch2_btree_node_hash_remove(struct btree_cache *bc, struct btree *b) void bch2_btree_node_hash_remove(struct btree_cache *bc, struct btree *b)
{ {
lockdep_assert_held(&bc->lock);
int ret = rhashtable_remove_fast(&bc->table, &b->hash, bch_btree_cache_params); int ret = rhashtable_remove_fast(&bc->table, &b->hash, bch_btree_cache_params);
BUG_ON(ret); BUG_ON(ret);
...@@ -195,6 +198,10 @@ void bch2_btree_node_hash_remove(struct btree_cache *bc, struct btree *b) ...@@ -195,6 +198,10 @@ void bch2_btree_node_hash_remove(struct btree_cache *bc, struct btree *b)
if (b->c.btree_id < BTREE_ID_NR) if (b->c.btree_id < BTREE_ID_NR)
--bc->nr_by_btree[b->c.btree_id]; --bc->nr_by_btree[b->c.btree_id];
bc->nr_live--;
bc->nr_freeable++;
list_move(&b->list, &bc->freeable);
} }
int __bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b) int __bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b)
...@@ -204,23 +211,25 @@ int __bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b) ...@@ -204,23 +211,25 @@ int __bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b)
int ret = rhashtable_lookup_insert_fast(&bc->table, &b->hash, int ret = rhashtable_lookup_insert_fast(&bc->table, &b->hash,
bch_btree_cache_params); bch_btree_cache_params);
if (!ret && b->c.btree_id < BTREE_ID_NR) if (ret)
bc->nr_by_btree[b->c.btree_id]++;
return ret; return ret;
if (b->c.btree_id < BTREE_ID_NR)
bc->nr_by_btree[b->c.btree_id]++;
bc->nr_live++;
bc->nr_freeable--;
list_move_tail(&b->list, &bc->live);
return 0;
} }
int bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b, int bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b,
unsigned level, enum btree_id id) unsigned level, enum btree_id id)
{ {
int ret;
b->c.level = level; b->c.level = level;
b->c.btree_id = id; b->c.btree_id = id;
mutex_lock(&bc->lock); mutex_lock(&bc->lock);
ret = __bch2_btree_node_hash_insert(bc, b); int ret = __bch2_btree_node_hash_insert(bc, b);
if (!ret)
list_add_tail(&b->list, &bc->live);
mutex_unlock(&bc->lock); mutex_unlock(&bc->lock);
return ret; return ret;
...@@ -402,7 +411,7 @@ static unsigned long bch2_btree_cache_scan(struct shrinker *shrink, ...@@ -402,7 +411,7 @@ static unsigned long bch2_btree_cache_scan(struct shrinker *shrink,
unsigned i, flags; unsigned i, flags;
unsigned long ret = SHRINK_STOP; unsigned long ret = SHRINK_STOP;
bool trigger_writes = atomic_long_read(&bc->nr_dirty) + nr >= bool trigger_writes = atomic_long_read(&bc->nr_dirty) + nr >=
bc->nr_used * 3 / 4; (bc->nr_live + bc->nr_freeable) * 3 / 4;
if (bch2_btree_shrinker_disabled) if (bch2_btree_shrinker_disabled)
return SHRINK_STOP; return SHRINK_STOP;
...@@ -451,11 +460,12 @@ static unsigned long bch2_btree_cache_scan(struct shrinker *shrink, ...@@ -451,11 +460,12 @@ static unsigned long bch2_btree_cache_scan(struct shrinker *shrink,
bc->not_freed[BCH_BTREE_CACHE_NOT_FREED_access_bit]++; bc->not_freed[BCH_BTREE_CACHE_NOT_FREED_access_bit]++;
--touched;; --touched;;
} else if (!btree_node_reclaim(c, b, true)) { } else if (!btree_node_reclaim(c, b, true)) {
bch2_btree_node_hash_remove(bc, b);
freed++; freed++;
btree_node_data_free(c, b); btree_node_data_free(c, b);
bc->nr_freed++; bc->nr_freed++;
bch2_btree_node_hash_remove(bc, b);
six_unlock_write(&b->c.lock); six_unlock_write(&b->c.lock);
six_unlock_intent(&b->c.lock); six_unlock_intent(&b->c.lock);
...@@ -506,7 +516,7 @@ static unsigned long bch2_btree_cache_count(struct shrinker *shrink, ...@@ -506,7 +516,7 @@ static unsigned long bch2_btree_cache_count(struct shrinker *shrink,
void bch2_fs_btree_cache_exit(struct bch_fs *c) void bch2_fs_btree_cache_exit(struct bch_fs *c)
{ {
struct btree_cache *bc = &c->btree_cache; struct btree_cache *bc = &c->btree_cache;
struct btree *b; struct btree *b, *t;
unsigned i, flags; unsigned i, flags;
shrinker_free(bc->shrink); shrinker_free(bc->shrink);
...@@ -527,11 +537,10 @@ void bch2_fs_btree_cache_exit(struct bch_fs *c) ...@@ -527,11 +537,10 @@ void bch2_fs_btree_cache_exit(struct bch_fs *c)
list_add(&r->b->list, &bc->live); list_add(&r->b->list, &bc->live);
} }
list_splice(&bc->freeable, &bc->live); list_for_each_entry_safe(b, t, &bc->live, list)
bch2_btree_node_hash_remove(bc, b);
while (!list_empty(&bc->live)) {
b = list_first_entry(&bc->live, struct btree, list);
list_for_each_entry_safe(b, t, &bc->freeable, list) {
BUG_ON(btree_node_read_in_flight(b) || BUG_ON(btree_node_read_in_flight(b) ||
btree_node_write_in_flight(b)); btree_node_write_in_flight(b));
...@@ -543,8 +552,7 @@ void bch2_fs_btree_cache_exit(struct bch_fs *c) ...@@ -543,8 +552,7 @@ void bch2_fs_btree_cache_exit(struct bch_fs *c)
list_splice(&bc->freed_pcpu, &bc->freed_nonpcpu); list_splice(&bc->freed_pcpu, &bc->freed_nonpcpu);
while (!list_empty(&bc->freed_nonpcpu)) { list_for_each_entry_safe(b, t, &bc->freed_nonpcpu, list) {
b = list_first_entry(&bc->freed_nonpcpu, struct btree, list);
list_del(&b->list); list_del(&b->list);
six_lock_exit(&b->c.lock); six_lock_exit(&b->c.lock);
kfree(b); kfree(b);
...@@ -553,6 +561,11 @@ void bch2_fs_btree_cache_exit(struct bch_fs *c) ...@@ -553,6 +561,11 @@ void bch2_fs_btree_cache_exit(struct bch_fs *c)
mutex_unlock(&bc->lock); mutex_unlock(&bc->lock);
memalloc_nofs_restore(flags); memalloc_nofs_restore(flags);
for (unsigned i = 0; i < ARRAY_SIZE(bc->nr_by_btree); i++)
BUG_ON(bc->nr_by_btree[i]);
BUG_ON(bc->nr_live);
BUG_ON(bc->nr_freeable);
if (bc->table_init_done) if (bc->table_init_done)
rhashtable_destroy(&bc->table); rhashtable_destroy(&bc->table);
} }
...@@ -739,7 +752,7 @@ struct btree *bch2_btree_node_mem_alloc(struct btree_trans *trans, bool pcpu_rea ...@@ -739,7 +752,7 @@ struct btree *bch2_btree_node_mem_alloc(struct btree_trans *trans, bool pcpu_rea
} }
mutex_lock(&bc->lock); mutex_lock(&bc->lock);
bc->nr_used++; bc->nr_freeable++;
got_mem: got_mem:
mutex_unlock(&bc->lock); mutex_unlock(&bc->lock);
...@@ -1280,8 +1293,8 @@ void bch2_btree_node_evict(struct btree_trans *trans, const struct bkey_i *k) ...@@ -1280,8 +1293,8 @@ void bch2_btree_node_evict(struct btree_trans *trans, const struct bkey_i *k)
BUG_ON(btree_node_dirty(b)); BUG_ON(btree_node_dirty(b));
mutex_lock(&bc->lock); mutex_lock(&bc->lock);
btree_node_data_free(c, b);
bch2_btree_node_hash_remove(bc, b); bch2_btree_node_hash_remove(bc, b);
btree_node_data_free(c, b);
mutex_unlock(&bc->lock); mutex_unlock(&bc->lock);
out: out:
six_unlock_write(&b->c.lock); six_unlock_write(&b->c.lock);
...@@ -1374,7 +1387,8 @@ void bch2_btree_cache_to_text(struct printbuf *out, const struct btree_cache *bc ...@@ -1374,7 +1387,8 @@ void bch2_btree_cache_to_text(struct printbuf *out, const struct btree_cache *bc
if (!out->nr_tabstops) if (!out->nr_tabstops)
printbuf_tabstop_push(out, 32); printbuf_tabstop_push(out, 32);
prt_btree_cache_line(out, c, "total:", bc->nr_used); prt_btree_cache_line(out, c, "nr_live:", bc->nr_live);
prt_btree_cache_line(out, c, "nr_freeable:", bc->nr_freeable);
prt_btree_cache_line(out, c, "nr dirty:", atomic_long_read(&bc->nr_dirty)); prt_btree_cache_line(out, c, "nr dirty:", atomic_long_read(&bc->nr_dirty));
prt_printf(out, "cannibalize lock:\t%p\n", bc->alloc_lock); prt_printf(out, "cannibalize lock:\t%p\n", bc->alloc_lock);
prt_newline(out); prt_newline(out);
......
...@@ -549,9 +549,8 @@ int bch2_check_topology(struct bch_fs *c) ...@@ -549,9 +549,8 @@ int bch2_check_topology(struct bch_fs *c)
six_unlock_read(&b->c.lock); six_unlock_read(&b->c.lock);
if (ret == DROP_THIS_NODE) { if (ret == DROP_THIS_NODE) {
bch2_btree_node_hash_remove(&c->btree_cache, b);
mutex_lock(&c->btree_cache.lock); mutex_lock(&c->btree_cache.lock);
list_move(&b->list, &c->btree_cache.freeable); bch2_btree_node_hash_remove(&c->btree_cache, b);
mutex_unlock(&c->btree_cache.lock); mutex_unlock(&c->btree_cache.lock);
r->b = NULL; r->b = NULL;
......
...@@ -1749,10 +1749,8 @@ static int __bch2_btree_root_read(struct btree_trans *trans, enum btree_id id, ...@@ -1749,10 +1749,8 @@ static int __bch2_btree_root_read(struct btree_trans *trans, enum btree_id id,
bch2_btree_node_read(trans, b, true); bch2_btree_node_read(trans, b, true);
if (btree_node_read_error(b)) { if (btree_node_read_error(b)) {
bch2_btree_node_hash_remove(&c->btree_cache, b);
mutex_lock(&c->btree_cache.lock); mutex_lock(&c->btree_cache.lock);
list_move(&b->list, &c->btree_cache.freeable); bch2_btree_node_hash_remove(&c->btree_cache, b);
mutex_unlock(&c->btree_cache.lock); mutex_unlock(&c->btree_cache.lock);
ret = -BCH_ERR_btree_node_read_error; ret = -BCH_ERR_btree_node_read_error;
......
...@@ -179,8 +179,8 @@ struct btree_cache { ...@@ -179,8 +179,8 @@ struct btree_cache {
struct list_head freed_pcpu; struct list_head freed_pcpu;
struct list_head freed_nonpcpu; struct list_head freed_nonpcpu;
/* Number of elements in live + freeable lists */ size_t nr_live;
size_t nr_used; size_t nr_freeable;
size_t nr_reserve; size_t nr_reserve;
size_t nr_by_btree[BTREE_ID_NR]; size_t nr_by_btree[BTREE_ID_NR];
atomic_long_t nr_dirty; atomic_long_t nr_dirty;
......
...@@ -251,8 +251,13 @@ static void bch2_btree_node_free_inmem(struct btree_trans *trans, ...@@ -251,8 +251,13 @@ static void bch2_btree_node_free_inmem(struct btree_trans *trans,
unsigned i, level = b->c.level; unsigned i, level = b->c.level;
bch2_btree_node_lock_write_nofail(trans, path, &b->c); bch2_btree_node_lock_write_nofail(trans, path, &b->c);
mutex_lock(&c->btree_cache.lock);
bch2_btree_node_hash_remove(&c->btree_cache, b); bch2_btree_node_hash_remove(&c->btree_cache, b);
mutex_unlock(&c->btree_cache.lock);
__btree_node_free(trans, b); __btree_node_free(trans, b);
six_unlock_write(&b->c.lock); six_unlock_write(&b->c.lock);
mark_btree_node_locked_noreset(path, level, BTREE_NODE_INTENT_LOCKED); mark_btree_node_locked_noreset(path, level, BTREE_NODE_INTENT_LOCKED);
...@@ -284,7 +289,6 @@ static void bch2_btree_node_free_never_used(struct btree_update *as, ...@@ -284,7 +289,6 @@ static void bch2_btree_node_free_never_used(struct btree_update *as,
clear_btree_node_need_write(b); clear_btree_node_need_write(b);
mutex_lock(&c->btree_cache.lock); mutex_lock(&c->btree_cache.lock);
list_del_init(&b->list);
bch2_btree_node_hash_remove(&c->btree_cache, b); bch2_btree_node_hash_remove(&c->btree_cache, b);
mutex_unlock(&c->btree_cache.lock); mutex_unlock(&c->btree_cache.lock);
......
...@@ -681,7 +681,7 @@ static int __bch2_journal_reclaim(struct journal *j, bool direct, bool kicked) ...@@ -681,7 +681,7 @@ static int __bch2_journal_reclaim(struct journal *j, bool direct, bool kicked)
if (j->watermark != BCH_WATERMARK_stripe) if (j->watermark != BCH_WATERMARK_stripe)
min_nr = 1; min_nr = 1;
if (atomic_long_read(&c->btree_cache.nr_dirty) * 2 > c->btree_cache.nr_used) if (atomic_long_read(&c->btree_cache.nr_dirty) * 2 > c->btree_cache.nr_live)
min_nr = 1; min_nr = 1;
min_key_cache = min(bch2_nr_btree_keys_need_flush(c), (size_t) 128); min_key_cache = min(bch2_nr_btree_keys_need_flush(c), (size_t) 128);
...@@ -690,7 +690,7 @@ static int __bch2_journal_reclaim(struct journal *j, bool direct, bool kicked) ...@@ -690,7 +690,7 @@ static int __bch2_journal_reclaim(struct journal *j, bool direct, bool kicked)
direct, kicked, direct, kicked,
min_nr, min_key_cache, min_nr, min_key_cache,
atomic_long_read(&c->btree_cache.nr_dirty), atomic_long_read(&c->btree_cache.nr_dirty),
c->btree_cache.nr_used, c->btree_cache.nr_live,
atomic_long_read(&c->btree_key_cache.nr_dirty), atomic_long_read(&c->btree_key_cache.nr_dirty),
atomic_long_read(&c->btree_key_cache.nr_keys)); atomic_long_read(&c->btree_key_cache.nr_keys));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment