summaryrefslogtreecommitdiff
path: root/fs/bcachefs/btree_io.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2022-02-27 05:35:16 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:09:26 +0300
commit39dcace83889f43d5619d07c2ec76c286c88a85b (patch)
tree5d02db8021dfdb61d8175fcad239f32a731d19eb /fs/bcachefs/btree_io.c
parent75ef2c59bc2f4d3c3ecd48286ac36ee7b868321c (diff)
downloadlinux-39dcace83889f43d5619d07c2ec76c286c88a85b.tar.xz
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.c25
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);
}
/*