bcachefs: Path must be locked if trans->locked && should_be_locked
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 10 Apr 2024 03:53:57 +0000 (23:53 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Fri, 23 May 2025 11:59:43 +0000 (07:59 -0400)
If path->should_be_locked is true, that means user code (of the btree
API) has seen, in this transaction, something guarded by the node this
path has locked, and we have to keep it locked until the end of the
transaction.

Assert that we're not violating this; should_be_locked should also be
cleared only in _very_ special situations.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_iter.c
fs/bcachefs/btree_iter.h
fs/bcachefs/btree_locking.c

index 77b91dd62d95afd1f99f9b6950b934c167e01200..97f3faac8067e5cee04e4f6fdd5b29b6112497bd 100644 (file)
@@ -1979,6 +1979,7 @@ struct btree *bch2_btree_iter_next_node(struct btree_trans *trans, struct btree_
 
        /* got to end? */
        if (!btree_path_node(path, path->level + 1)) {
+               path->should_be_locked = false;
                btree_path_set_level_up(trans, path);
                return NULL;
        }
index 7cb2c38b70c0a6d80bb7bfc06fc49730e58b0391..2cabb5f0f484c616cd5e46eece4574c7e40e2d51 100644 (file)
@@ -50,6 +50,7 @@ static inline void btree_path_set_dirty(struct btree_trans *trans,
                                        struct btree_path *path,
                                        enum btree_path_uptodate u)
 {
+       BUG_ON(path->should_be_locked && trans->locked && !trans->restarted);
        path->uptodate = max_t(unsigned, path->uptodate, u);
 }
 
index 2cdc9a04f3e8d762bb8cbe2c8a8e61db4035aa80..2f2aed0c9916c10a4b4cd7f6266ea5fcd4073944 100644 (file)
@@ -882,14 +882,15 @@ int __bch2_trans_mutex_lock(struct btree_trans *trans,
 
 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;