summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2024-04-09 23:53:57 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2025-04-29 13:44:31 -0400
commitcf9d9bb38b6e04462ab01c130fb15b5b360db810 (patch)
tree1d1eb004a70b1d0f407a0937a1b36092431ded49
parentfce82ecdd2010b9dda57c6bef6689c66f8a42e93 (diff)
bcachefs: Path must be locked if trans->locked && path->should_be_locked
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/btree_iter.c4
-rw-r--r--fs/bcachefs/btree_locking.c36
-rw-r--r--fs/bcachefs/btree_locking.h11
-rw-r--r--fs/bcachefs/btree_update_interior.c5
4 files changed, 33 insertions, 23 deletions
diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c
index bfd97d08a15a..56349265970d 100644
--- a/fs/bcachefs/btree_iter.c
+++ b/fs/bcachefs/btree_iter.c
@@ -232,7 +232,7 @@ static void bch2_btree_path_verify(struct btree_trans *trans,
bch2_btree_path_verify_level(trans, path, i);
}
- bch2_btree_path_verify_locks(path);
+ bch2_btree_path_verify_locks(trans, path);
}
void bch2_trans_verify_paths(struct btree_trans *trans)
@@ -977,7 +977,7 @@ static __always_inline int btree_path_down(struct btree_trans *trans,
path->level = level;
bch2_btree_path_level_init(trans, path, b);
- bch2_btree_path_verify_locks(path);
+ bch2_btree_path_verify_locks(trans, path);
err:
bch2_bkey_buf_exit(&tmp, c);
return ret;
diff --git a/fs/bcachefs/btree_locking.c b/fs/bcachefs/btree_locking.c
index 9cd496fc05a1..8b7c6508f8ed 100644
--- a/fs/bcachefs/btree_locking.c
+++ b/fs/bcachefs/btree_locking.c
@@ -620,7 +620,7 @@ bool bch2_btree_path_upgrade_nounlock(struct btree_trans *trans,
}
}
- bch2_btree_path_verify_locks(path);
+ bch2_btree_path_verify_locks(trans, path);
return path->locks_want == new_locks_want;
}
@@ -648,8 +648,10 @@ bool __bch2_btree_path_upgrade(struct btree_trans *trans,
path->locks_want = new_locks_want;
bool ret = btree_path_get_locks(trans, path, true, f);
- if (ret)
- goto out;
+ if (ret) {
+ bch2_trans_verify_locks(trans);
+ return true;
+ }
/*
* XXX: this is ugly - we'd prefer to not be mucking with other
@@ -683,9 +685,8 @@ bool __bch2_btree_path_upgrade(struct btree_trans *trans,
btree_path_get_locks(trans, linked, true, NULL);
}
}
-out:
- bch2_trans_verify_locks(trans);
- return ret;
+
+ return false;
}
void __bch2_btree_path_downgrade(struct btree_trans *trans,
@@ -714,7 +715,7 @@ void __bch2_btree_path_downgrade(struct btree_trans *trans,
}
}
- bch2_btree_path_verify_locks(path);
+ bch2_btree_path_verify_locks(trans, path);
trace_path_downgrade(trans, _RET_IP_, path, old_locks_want);
}
@@ -852,16 +853,17 @@ int __bch2_trans_mutex_lock(struct btree_trans *trans,
#ifdef CONFIG_BCACHEFS_DEBUG
-void bch2_btree_path_verify_locks(struct btree_path *path)
+void bch2_btree_path_verify_locks(struct btree_trans *trans, struct btree_path *path)
{
- /*
- * A path may be uptodate and yet have nothing locked if and only if
- * there is no node at path->level, which generally means we were
- * iterating over all nodes and got to the end of the btree
- */
- BUG_ON(path->uptodate == BTREE_ITER_UPTODATE &&
- btree_path_node(path, path->level) &&
- !path->nodes_locked);
+ if (!path->nodes_locked && btree_path_node(path, path->level)) {
+ /*
+ * A path may be uptodate and yet have nothing locked if and only if
+ * there is no node at path->level, which generally means we were
+ * iterating over all nodes and got to the end of the btree
+ */
+ BUG_ON(path->uptodate == BTREE_ITER_UPTODATE);
+ BUG_ON(path->should_be_locked && trans->locked && !trans->restarted);
+ }
if (!path->nodes_locked)
return;
@@ -904,7 +906,7 @@ void bch2_trans_verify_locks(struct btree_trans *trans)
unsigned i;
trans_for_each_path(trans, path, i)
- bch2_btree_path_verify_locks(path);
+ bch2_btree_path_verify_locks(trans, path);
}
#endif
diff --git a/fs/bcachefs/btree_locking.h b/fs/bcachefs/btree_locking.h
index 568d4794e562..97754cd68a57 100644
--- a/fs/bcachefs/btree_locking.h
+++ b/fs/bcachefs/btree_locking.h
@@ -14,10 +14,10 @@
#include "six.h"
#ifdef CONFIG_BCACHEFS_DEBUG
-void bch2_btree_path_verify_locks(struct btree_path *);
+void bch2_btree_path_verify_locks(struct btree_trans *, struct btree_path *);
void bch2_trans_verify_locks(struct btree_trans *);
#else
-static inline void bch2_btree_path_verify_locks(struct btree_path *path) {}
+static inline void bch2_btree_path_verify_locks(struct btree_trans *, struct btree_path *path) {}
static inline void bch2_trans_verify_locks(struct btree_trans *trans) {}
#endif
@@ -165,6 +165,13 @@ static inline void __bch2_btree_path_unlock(struct btree_trans *trans,
btree_node_unlock(trans, path, btree_path_lowest_level_locked(path));
}
+static inline void bch2_btree_path_unlock_dontneed(struct btree_trans *trans,
+ struct btree_path *path)
+{
+ path->should_be_locked = false;
+ __bch2_btree_path_unlock(trans, path);
+}
+
/*
* Updates the saved lock sequence number, so that bch2_btree_node_relock() will
* succeed:
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c
index 50790a919c52..17772094e43c 100644
--- a/fs/bcachefs/btree_update_interior.c
+++ b/fs/bcachefs/btree_update_interior.c
@@ -1611,6 +1611,7 @@ static int btree_split(struct btree_update *as, struct btree_trans *trans,
u64 start_time = local_clock();
int ret = 0;
+ bch2_trans_verify_locks(trans);
bch2_verify_btree_nr_keys(b);
BUG_ON(!parent && (b != btree_node_root(c, b)));
BUG_ON(parent && !btree_node_intent_locked(trans->paths + path, b->c.level + 1));
@@ -1749,11 +1750,11 @@ static int btree_split(struct btree_update *as, struct btree_trans *trans,
bch2_trans_node_add(trans, trans->paths + path1, n1);
out:
if (path2) {
- __bch2_btree_path_unlock(trans, trans->paths + path2);
+ bch2_btree_path_unlock_dontneed(trans, trans->paths + path2);
bch2_path_put(trans, path2, true);
}
if (path1) {
- __bch2_btree_path_unlock(trans, trans->paths + path1);
+ bch2_btree_path_unlock_dontneed(trans, trans->paths + path1);
bch2_path_put(trans, path1, true);
}