diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2020-06-12 14:58:07 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:08:41 -0400 |
commit | 515282ac7d847d567dd3ba802edf34316368bb14 (patch) | |
tree | bf4b1cf0cbd0826e8899bf9c1b0c907d4cd38aed /fs/bcachefs/btree_locking.h | |
parent | 4e8224ed8ab3c671bb96b6b98c8f8de14637440d (diff) | |
download | lwn-515282ac7d847d567dd3ba802edf34316368bb14.tar.gz lwn-515282ac7d847d567dd3ba802edf34316368bb14.zip |
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.h | 24 |
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; } |