bcachefs: Fix locking in btree_node_write_done()
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 27 Feb 2022 02:35:16 +0000 (21:35 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:26 +0000 (17:09 -0400)
There was a rare recursive locking bug, in __bch2_btree_node_write()
nowrite path -> btree_node_write_done(), in the path that kicks off
another write.

This splits out an inner __btree_node_write_done() that expects to be
run with the btree node lock held.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
fs/bcachefs/btree_io.c

index fd7f2a78473c38b1d79c50f20ed4a1c49a61441b..f4d6a6c5096de444fc42bb4ced5508f320a9c31e 100644 (file)
@@ -1592,29 +1592,13 @@ void bch2_btree_complete_write(struct bch_fs *c, struct btree *b,
        bch2_journal_pin_drop(&c->journal, &w->journal);
 }
 
-static void btree_node_write_done(struct bch_fs *c, struct btree *b)
+static void __btree_node_write_done(struct bch_fs *c, struct btree *b)
 {
        struct btree_write *w = btree_prev_write(b);
        unsigned long old, new, v;
 
        bch2_btree_complete_write(c, b, w);
 
-       v = READ_ONCE(b->flags);
-       do {
-               old = new = v;
-
-               if (old & (1U << BTREE_NODE_need_write))
-                       goto do_write;
-
-               new &= ~(1U << BTREE_NODE_write_in_flight);
-               new &= ~(1U << BTREE_NODE_write_in_flight_inner);
-       } while ((v = cmpxchg(&b->flags, old, new)) != old);
-
-       wake_up_bit(&b->flags, BTREE_NODE_write_in_flight);
-       return;
-
-do_write:
-       six_lock_read(&b->c.lock, NULL, NULL);
        v = READ_ONCE(b->flags);
        do {
                old = new = v;
@@ -1637,7 +1621,12 @@ do_write:
 
        if (new & (1U << BTREE_NODE_write_in_flight))
                __bch2_btree_node_write(c, b, true);
+}
 
+static void btree_node_write_done(struct bch_fs *c, struct btree *b)
+{
+       six_lock_read(&b->c.lock, NULL, NULL);
+       __btree_node_write_done(c, b);
        six_unlock_read(&b->c.lock);
 }
 
@@ -1992,7 +1981,7 @@ err:
        b->written += sectors_to_write;
 nowrite:
        btree_bounce_free(c, bytes, used_mempool, data);
-       btree_node_write_done(c, b);
+       __btree_node_write_done(c, b);
 }
 
 /*