bcachefs: Fix a deadlock in btree_update_nodes_written()
authorKent Overstreet <kent.overstreet@linux.dev>
Mon, 3 Oct 2022 20:41:17 +0000 (16:41 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:42 +0000 (17:09 -0400)
btree_node_lock_nopath() is something we'd like to get rid of, it's
always prone to deadlocks if we accidentally are holding other locks,
because it doesn't mark the lock it's taking in a path: we'll want to
get rid of it in the future, but for now this patch works it by calling
bch2_trans_unlock().

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

index fd44492150b05eecc05d0ee37ea36c118bbb14aa..247555dffa3f909d227914a9e4860310d3eb82f1 100644 (file)
@@ -650,6 +650,17 @@ err:
                 * we're in journal error state:
                 */
 
+               /*
+                * Ensure transaction is unlocked before using
+                * btree_node_lock_nopath() (the use of which is always suspect,
+                * we need to work on removing this in the future)
+                *
+                * It should be, but get_unlocked_mut_path() -> bch2_path_get()
+                * calls bch2_path_upgrade(), before we call path_make_mut(), so
+                * we may rarely end up with a locked path besides the one we
+                * have here:
+                */
+               bch2_trans_unlock(&trans);
                btree_node_lock_nopath_nofail(&trans, &b->c, SIX_LOCK_intent);
                mark_btree_node_locked(&trans, path, b->c.level, SIX_LOCK_intent);
                path->l[b->c.level].lock_seq = b->c.lock.state.seq;