summaryrefslogtreecommitdiff
path: root/fs/bcachefs/btree_locking.h
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2020-06-12 21:58:07 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:08:41 +0300
commit515282ac7d847d567dd3ba802edf34316368bb14 (patch)
treebf4b1cf0cbd0826e8899bf9c1b0c907d4cd38aed /fs/bcachefs/btree_locking.h
parent4e8224ed8ab3c671bb96b6b98c8f8de14637440d (diff)
downloadlinux-515282ac7d847d567dd3ba802edf34316368bb14.tar.xz
bcachefs: Fix a deadlock
__bch2_btree_node_lock() was incorrectly using iter->pos as a proxy for btree node lock ordering, this caused an off by one error that was triggered by bch2_btree_node_get_sibling() getting the previous node. This refactors the code to compare against btree node keys directly. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/btree_locking.h')
-rw-r--r--fs/bcachefs/btree_locking.h24
1 files changed, 14 insertions, 10 deletions
diff --git a/fs/bcachefs/btree_locking.h b/fs/bcachefs/btree_locking.h
index cf1801ee14a2..4c80ab368e69 100644
--- a/fs/bcachefs/btree_locking.h
+++ b/fs/bcachefs/btree_locking.h
@@ -157,15 +157,15 @@ static inline void btree_node_lock_type(struct bch_fs *c, struct btree *b,
* Lock a btree node if we already have it locked on one of our linked
* iterators:
*/
-static inline bool btree_node_lock_increment(struct btree_iter *iter,
+static inline bool btree_node_lock_increment(struct btree_trans *trans,
struct btree *b, unsigned level,
enum btree_node_locked_type want)
{
- struct btree_iter *linked;
+ struct btree_iter *iter;
- trans_for_each_iter(iter->trans, linked)
- if (linked->l[level].b == b &&
- btree_node_locked_type(linked, level) >= want) {
+ trans_for_each_iter(trans, iter)
+ if (iter->l[level].b == b &&
+ btree_node_locked_type(iter, level) >= want) {
six_lock_increment(&b->c.lock, want);
return true;
}
@@ -181,19 +181,23 @@ static inline bool btree_node_lock(struct btree *b, struct bpos pos,
struct btree_iter *iter,
enum six_lock_type type)
{
+ struct btree_trans *trans = iter->trans;
bool ret;
EBUG_ON(level >= BTREE_MAX_DEPTH);
#ifdef CONFIG_BCACHEFS_DEBUG
- iter->trans->locking = b;
+ trans->locking = b;
+ trans->locking_iter_idx = iter->idx;
+ trans->locking_pos = pos;
+ trans->locking_btree_id = iter->btree_id;
+ trans->locking_level = level;
#endif
-
- ret = likely(six_trylock_type(&b->c.lock, type)) ||
- btree_node_lock_increment(iter, b, level, type) ||
+ ret = likely(six_trylock_type(&b->c.lock, type)) ||
+ btree_node_lock_increment(trans, b, level, type) ||
__bch2_btree_node_lock(b, pos, level, iter, type);
#ifdef CONFIG_BCACHEFS_DEBUG
- iter->trans->locking = NULL;
+ trans->locking = NULL;
#endif
return ret;
}