Commit 8cad3e2f authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Use cached iterators for inode updates

This switches inode updates to use cached btree iterators - which should
be a nice performance boost, since lock contention on the inodes btree
can be a bottleneck on multithreaded workloads.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent e7b854b1
...@@ -28,8 +28,8 @@ static const struct rhashtable_params bch2_btree_key_cache_params = { ...@@ -28,8 +28,8 @@ static const struct rhashtable_params bch2_btree_key_cache_params = {
}; };
__flatten __flatten
static inline struct bkey_cached * inline struct bkey_cached *
btree_key_cache_find(struct bch_fs *c, enum btree_id btree_id, struct bpos pos) bch2_btree_key_cache_find(struct bch_fs *c, enum btree_id btree_id, struct bpos pos)
{ {
struct bkey_cached_key key = { struct bkey_cached_key key = {
.btree_id = btree_id, .btree_id = btree_id,
...@@ -218,7 +218,7 @@ int bch2_btree_iter_traverse_cached(struct btree_iter *iter) ...@@ -218,7 +218,7 @@ int bch2_btree_iter_traverse_cached(struct btree_iter *iter)
goto fill; goto fill;
} }
retry: retry:
ck = btree_key_cache_find(c, iter->btree_id, iter->pos); ck = bch2_btree_key_cache_find(c, iter->btree_id, iter->pos);
if (!ck) { if (!ck) {
if (iter->flags & BTREE_ITER_CACHED_NOCREATE) { if (iter->flags & BTREE_ITER_CACHED_NOCREATE) {
iter->l[0].b = NULL; iter->l[0].b = NULL;
...@@ -415,7 +415,7 @@ int bch2_btree_key_cache_flush(struct btree_trans *trans, ...@@ -415,7 +415,7 @@ int bch2_btree_key_cache_flush(struct btree_trans *trans,
struct bkey_cached_key key = { id, pos }; struct bkey_cached_key key = { id, pos };
/* Fastpath - assume it won't be found: */ /* Fastpath - assume it won't be found: */
if (!btree_key_cache_find(c, id, pos)) if (!bch2_btree_key_cache_find(c, id, pos))
return 0; return 0;
return btree_key_cache_flush_pos(trans, key, 0, true); return btree_key_cache_flush_pos(trans, key, 0, true);
...@@ -462,7 +462,7 @@ bool bch2_btree_insert_key_cached(struct btree_trans *trans, ...@@ -462,7 +462,7 @@ bool bch2_btree_insert_key_cached(struct btree_trans *trans,
void bch2_btree_key_cache_verify_clean(struct btree_trans *trans, void bch2_btree_key_cache_verify_clean(struct btree_trans *trans,
enum btree_id id, struct bpos pos) enum btree_id id, struct bpos pos)
{ {
BUG_ON(btree_key_cache_find(trans->c, id, pos)); BUG_ON(bch2_btree_key_cache_find(trans->c, id, pos));
} }
#endif #endif
......
#ifndef _BCACHEFS_BTREE_KEY_CACHE_H #ifndef _BCACHEFS_BTREE_KEY_CACHE_H
#define _BCACHEFS_BTREE_KEY_CACHE_H #define _BCACHEFS_BTREE_KEY_CACHE_H
struct bkey_cached *
bch2_btree_key_cache_find(struct bch_fs *, enum btree_id, struct bpos);
int bch2_btree_iter_traverse_cached(struct btree_iter *); int bch2_btree_iter_traverse_cached(struct btree_iter *);
bool bch2_btree_insert_key_cached(struct btree_trans *, bool bch2_btree_insert_key_cached(struct btree_trans *,
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include "bcachefs.h" #include "bcachefs.h"
#include "btree_key_cache.h"
#include "bkey_methods.h" #include "bkey_methods.h"
#include "btree_update.h" #include "btree_update.h"
#include "error.h" #include "error.h"
...@@ -189,11 +190,11 @@ struct btree_iter *bch2_inode_peek(struct btree_trans *trans, ...@@ -189,11 +190,11 @@ struct btree_iter *bch2_inode_peek(struct btree_trans *trans,
int ret; int ret;
iter = bch2_trans_get_iter(trans, BTREE_ID_INODES, POS(0, inum), iter = bch2_trans_get_iter(trans, BTREE_ID_INODES, POS(0, inum),
BTREE_ITER_SLOTS|flags); BTREE_ITER_CACHED|flags);
if (IS_ERR(iter)) if (IS_ERR(iter))
return iter; return iter;
k = bch2_btree_iter_peek_slot(iter); k = bch2_btree_iter_peek_cached(iter);
ret = bkey_err(k); ret = bkey_err(k);
if (ret) if (ret)
goto err; goto err;
...@@ -390,7 +391,17 @@ int bch2_inode_create(struct btree_trans *trans, ...@@ -390,7 +391,17 @@ int bch2_inode_create(struct btree_trans *trans,
if (bkey_cmp(iter->pos, POS(0, max)) > 0) if (bkey_cmp(iter->pos, POS(0, max)) > 0)
break; break;
if (k.k->type != KEY_TYPE_inode) /*
* There's a potential cache coherency issue with the btree key
* cache code here - we're iterating over the btree, skipping
* that cache. We should never see an empty slot that isn't
* actually empty due to a pending update in the key cache
* because the update that creates the inode isn't done with a
* cached iterator, but - better safe than sorry, check the
* cache before using a slot:
*/
if (k.k->type != KEY_TYPE_inode &&
!bch2_btree_key_cache_find(trans->c, BTREE_ID_INODES, iter->pos))
goto found_slot; goto found_slot;
} }
...@@ -424,6 +435,8 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr) ...@@ -424,6 +435,8 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
struct bkey_i_inode_generation delete; struct bkey_i_inode_generation delete;
struct bpos start = POS(inode_nr, 0); struct bpos start = POS(inode_nr, 0);
struct bpos end = POS(inode_nr + 1, 0); struct bpos end = POS(inode_nr + 1, 0);
struct bkey_s_c k;
u64 bi_generation;
int ret; int ret;
/* /*
...@@ -444,51 +457,62 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr) ...@@ -444,51 +457,62 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
return ret; return ret;
bch2_trans_init(&trans, c, 0, 0); bch2_trans_init(&trans, c, 0, 0);
retry:
bch2_trans_begin(&trans);
bi_generation = 0;
ret = bch2_btree_key_cache_flush(&trans, BTREE_ID_INODES, POS(0, inode_nr));
if (ret) {
if (ret != -EINTR)
bch_err(c, "error flushing btree key cache: %i", ret);
goto err;
}
iter = bch2_trans_get_iter(&trans, BTREE_ID_INODES, POS(0, inode_nr), iter = bch2_trans_get_iter(&trans, BTREE_ID_INODES, POS(0, inode_nr),
BTREE_ITER_SLOTS|BTREE_ITER_INTENT); BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
do { k = bch2_btree_iter_peek_slot(iter);
struct bkey_s_c k = bch2_btree_iter_peek_slot(iter);
u32 bi_generation = 0;
ret = bkey_err(k); ret = bkey_err(k);
if (ret) if (ret)
break; goto err;
bch2_fs_inconsistent_on(k.k->type != KEY_TYPE_inode, c, bch2_fs_inconsistent_on(k.k->type != KEY_TYPE_inode, c,
"inode %llu not found when deleting", "inode %llu not found when deleting",
inode_nr); inode_nr);
switch (k.k->type) { switch (k.k->type) {
case KEY_TYPE_inode: { case KEY_TYPE_inode: {
struct bch_inode_unpacked inode_u; struct bch_inode_unpacked inode_u;
if (!bch2_inode_unpack(bkey_s_c_to_inode(k), &inode_u)) if (!bch2_inode_unpack(bkey_s_c_to_inode(k), &inode_u))
bi_generation = inode_u.bi_generation + 1; bi_generation = inode_u.bi_generation + 1;
break; break;
} }
case KEY_TYPE_inode_generation: { case KEY_TYPE_inode_generation: {
struct bkey_s_c_inode_generation g = struct bkey_s_c_inode_generation g =
bkey_s_c_to_inode_generation(k); bkey_s_c_to_inode_generation(k);
bi_generation = le32_to_cpu(g.v->bi_generation); bi_generation = le32_to_cpu(g.v->bi_generation);
break; break;
} }
} }
if (!bi_generation) { if (!bi_generation) {
bkey_init(&delete.k); bkey_init(&delete.k);
delete.k.p.offset = inode_nr; delete.k.p.offset = inode_nr;
} else { } else {
bkey_inode_generation_init(&delete.k_i); bkey_inode_generation_init(&delete.k_i);
delete.k.p.offset = inode_nr; delete.k.p.offset = inode_nr;
delete.v.bi_generation = cpu_to_le32(bi_generation); delete.v.bi_generation = cpu_to_le32(bi_generation);
} }
bch2_trans_update(&trans, iter, &delete.k_i, 0); bch2_trans_update(&trans, iter, &delete.k_i, 0);
ret = bch2_trans_commit(&trans, NULL, NULL, ret = bch2_trans_commit(&trans, NULL, NULL,
BTREE_INSERT_NOFAIL); BTREE_INSERT_NOFAIL);
} while (ret == -EINTR); err:
if (ret == -EINTR)
goto retry;
bch2_trans_exit(&trans); bch2_trans_exit(&trans);
return ret; return ret;
...@@ -502,11 +526,11 @@ int bch2_inode_find_by_inum_trans(struct btree_trans *trans, u64 inode_nr, ...@@ -502,11 +526,11 @@ int bch2_inode_find_by_inum_trans(struct btree_trans *trans, u64 inode_nr,
int ret; int ret;
iter = bch2_trans_get_iter(trans, BTREE_ID_INODES, iter = bch2_trans_get_iter(trans, BTREE_ID_INODES,
POS(0, inode_nr), BTREE_ITER_SLOTS); POS(0, inode_nr), BTREE_ITER_CACHED);
if (IS_ERR(iter)) if (IS_ERR(iter))
return PTR_ERR(iter); return PTR_ERR(iter);
k = bch2_btree_iter_peek_slot(iter); k = bch2_btree_iter_peek_cached(iter);
ret = bkey_err(k); ret = bkey_err(k);
if (ret) if (ret)
goto err; goto err;
......
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