From 2e8d686a4a13c01d9a2b329507a0f5ce6455b5a8 Mon Sep 17 00:00:00 2001 From: Kent Overstreet <kent.overstreet@linux.dev> Date: Tue, 4 Jun 2024 18:31:13 -0400 Subject: [PATCH] bcachefs: Coalesce accounting keys before journal replay This fixes a performance regression in journal replay; without colaescing accounting keys we have multiple keys at the same position, which means journal_keys_peek_upto() has to skip past many overwritten keys - turning journal replay into an O(n^2) algorithm. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev> --- fs/bcachefs/btree_journal_iter.h | 2 ++ fs/bcachefs/disk_accounting.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/fs/bcachefs/btree_journal_iter.h b/fs/bcachefs/btree_journal_iter.h index 5b66c8f85fc1..1653de9d609b 100644 --- a/fs/bcachefs/btree_journal_iter.h +++ b/fs/bcachefs/btree_journal_iter.h @@ -2,6 +2,8 @@ #ifndef _BCACHEFS_BTREE_JOURNAL_ITER_H #define _BCACHEFS_BTREE_JOURNAL_ITER_H +#include "bkey.h" + struct journal_iter { struct list_head list; enum btree_id btree_id; diff --git a/fs/bcachefs/disk_accounting.c b/fs/bcachefs/disk_accounting.c index 2cc2e0f8cb53..dbdc16f2fc1c 100644 --- a/fs/bcachefs/disk_accounting.c +++ b/fs/bcachefs/disk_accounting.c @@ -2,6 +2,7 @@ #include "bcachefs.h" #include "bcachefs_ioctl.h" +#include "btree_journal_iter.h" #include "btree_update.h" #include "btree_write_buffer.h" #include "buckets.h" @@ -344,7 +345,9 @@ int bch2_accounting_read(struct bch_fs *c) goto err; struct journal_keys *keys = &c->journal_keys; + struct journal_key *dst = keys->data; move_gap(keys, keys->nr); + darray_for_each(*keys, i) { if (i->k->k.type == KEY_TYPE_accounting) { struct bkey_s_c k = bkey_i_to_s_c(i->k); @@ -358,11 +361,26 @@ int bch2_accounting_read(struct bch_fs *c) if (applied) continue; + if (i + 1 < &darray_top(*keys) && + i[1].k->k.type == KEY_TYPE_accounting && + !journal_key_cmp(i, i + 1)) { + BUG_ON(bversion_cmp(i[0].k->k.version, i[1].k->k.version) >= 0); + + i[1].journal_seq = i[0].journal_seq; + + bch2_accounting_accumulate(bkey_i_to_accounting(i[1].k), + bkey_s_c_to_accounting(k)); + continue; + } + ret = accounting_read_key(c, k); if (ret) goto err; } + + *dst++ = *i; } + keys->gap = keys->nr = dst - keys->data; percpu_down_read(&c->mark_lock); preempt_disable();