summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2020-10-28 14:18:18 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:08:45 -0400
commitdcf141b9e13d261629806aa37e0fa7769d38b789 (patch)
tree6b3cc275777d538d4b53277ad09348b60b7d3a83
parenta301dc38efa178e900a59ce7f03c1e81123c0919 (diff)
bcachefs: Fix spurious transaction restarts
The check for whether locking a btree node would deadlock was wrong - we have to check that interior nodes are locked before descendents, but this check was wrong when consider cached vs. non cached iterators. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/btree_iter.c1
-rw-r--r--fs/bcachefs/btree_types.h5
2 files changed, 6 insertions, 0 deletions
diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c
index a76e13000d11..d310b2389e38 100644
--- a/fs/bcachefs/btree_iter.c
+++ b/fs/bcachefs/btree_iter.c
@@ -244,6 +244,7 @@ bool __bch2_btree_node_lock(struct btree *b, struct bpos pos,
* we're about to lock, it must have the ancestors locked too:
*/
if (linked->btree_id == iter->btree_id &&
+ btree_iter_is_cached(linked) == btree_iter_is_cached(iter) &&
level > __fls(linked->nodes_locked)) {
if (!(trans->nounlock)) {
linked->locks_want =
diff --git a/fs/bcachefs/btree_types.h b/fs/bcachefs/btree_types.h
index f02518f9d9ec..d4f0db1fe457 100644
--- a/fs/bcachefs/btree_types.h
+++ b/fs/bcachefs/btree_types.h
@@ -283,6 +283,11 @@ btree_iter_type(const struct btree_iter *iter)
return iter->flags & BTREE_ITER_TYPE;
}
+static inline bool btree_iter_is_cached(const struct btree_iter *iter)
+{
+ return btree_iter_type(iter) == BTREE_ITER_CACHED;
+}
+
static inline struct btree_iter_level *iter_l(struct btree_iter *iter)
{
return iter->l + iter->level;