summaryrefslogtreecommitdiff
path: root/fs/bcachefs/btree_io.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2022-11-18 00:03:15 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:09:46 +0300
commit42af0ad569edbfcd252e9abf0badd97b895c34be (patch)
treeae24fa72c52e7f8ed6797a98cae59fdae556f543 /fs/bcachefs/btree_io.c
parent7fec8266af12b655e98978050e716e12e8544fe6 (diff)
downloadlinux-42af0ad569edbfcd252e9abf0badd97b895c34be.tar.xz
bcachefs: Fix a race with b->write_type
b->write_type needs to be set atomically with setting the btree_node_need_write flag, so move it into b->flags. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/btree_io.c')
-rw-r--r--fs/bcachefs/btree_io.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/fs/bcachefs/btree_io.c b/fs/bcachefs/btree_io.c
index 5d750f447241..8dbe930c1eb2 100644
--- a/fs/bcachefs/btree_io.c
+++ b/fs/bcachefs/btree_io.c
@@ -1636,6 +1636,7 @@ 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;
+ unsigned type = 0;
bch2_btree_complete_write(c, b, w);
@@ -1654,6 +1655,9 @@ static void __btree_node_write_done(struct bch_fs *c, struct btree *b)
new |= (1U << BTREE_NODE_write_in_flight_inner);
new |= (1U << BTREE_NODE_just_written);
new ^= (1U << BTREE_NODE_write_idx);
+
+ type = new & BTREE_WRITE_TYPE_MASK;
+ new &= ~BTREE_WRITE_TYPE_MASK;
} else {
new &= ~(1U << BTREE_NODE_write_in_flight);
new &= ~(1U << BTREE_NODE_write_in_flight_inner);
@@ -1661,7 +1665,7 @@ static void __btree_node_write_done(struct bch_fs *c, struct btree *b)
} while ((v = cmpxchg(&b->flags, old, new)) != old);
if (new & (1U << BTREE_NODE_write_in_flight))
- __bch2_btree_node_write(c, b, BTREE_WRITE_ALREADY_STARTED|b->write_type);
+ __bch2_btree_node_write(c, b, BTREE_WRITE_ALREADY_STARTED|type);
else
wake_up_bit(&b->flags, BTREE_NODE_write_in_flight);
}
@@ -1846,6 +1850,10 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b, unsigned flags)
if (old & (1 << BTREE_NODE_write_in_flight))
return;
+ if (flags & BTREE_WRITE_ONLY_IF_NEED)
+ type = new & BTREE_WRITE_TYPE_MASK;
+ new &= ~BTREE_WRITE_TYPE_MASK;
+
new &= ~(1 << BTREE_NODE_dirty);
new &= ~(1 << BTREE_NODE_need_write);
new |= (1 << BTREE_NODE_write_in_flight);
@@ -1857,10 +1865,6 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b, unsigned flags)
if (new & (1U << BTREE_NODE_need_write))
return;
do_write:
- if ((flags & BTREE_WRITE_ONLY_IF_NEED))
- type = b->write_type;
- b->write_type = 0;
-
BUG_ON((type == BTREE_WRITE_initial) != (b->written == 0));
atomic_dec(&c->btree_cache.dirty);