diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-02-26 21:35:16 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:09:26 -0400 |
commit | 39dcace83889f43d5619d07c2ec76c286c88a85b (patch) | |
tree | 5d02db8021dfdb61d8175fcad239f32a731d19eb /fs/bcachefs/btree_io.c | |
parent | 75ef2c59bc2f4d3c3ecd48286ac36ee7b868321c (diff) |
bcachefs: Fix locking in btree_node_write_done()
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>
Diffstat (limited to 'fs/bcachefs/btree_io.c')
-rw-r--r-- | fs/bcachefs/btree_io.c | 25 |
1 files changed, 7 insertions, 18 deletions
diff --git a/fs/bcachefs/btree_io.c b/fs/bcachefs/btree_io.c index fd7f2a78473c..f4d6a6c5096d 100644 --- a/fs/bcachefs/btree_io.c +++ b/fs/bcachefs/btree_io.c @@ -1592,7 +1592,7 @@ 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; @@ -1603,22 +1603,6 @@ static void btree_node_write_done(struct bch_fs *c, struct btree *b) 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; - if ((old & (1U << BTREE_NODE_dirty)) && (old & (1U << BTREE_NODE_need_write)) && !(old & (1U << BTREE_NODE_never_write)) && @@ -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); } /* |