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>
This commit is contained in:
parent
7fec8266af
commit
42af0ad569
@ -627,23 +627,6 @@ typedef struct {
|
||||
#define BCACHEFS_ROOT_SUBVOL_INUM \
|
||||
((subvol_inum) { BCACHEFS_ROOT_SUBVOL, BCACHEFS_ROOT_INO })
|
||||
|
||||
#define BCH_BTREE_WRITE_TYPES() \
|
||||
x(initial, 0) \
|
||||
x(init_next_bset, 1) \
|
||||
x(cache_reclaim, 2) \
|
||||
x(journal_reclaim, 3) \
|
||||
x(interior, 4)
|
||||
|
||||
enum btree_write_type {
|
||||
#define x(t, n) BTREE_WRITE_##t,
|
||||
BCH_BTREE_WRITE_TYPES()
|
||||
#undef x
|
||||
BTREE_WRITE_TYPE_NR,
|
||||
};
|
||||
|
||||
#define BTREE_WRITE_TYPE_MASK (roundup_pow_of_two(BTREE_WRITE_TYPE_NR) - 1)
|
||||
#define BTREE_WRITE_TYPE_BITS ilog2(BTREE_WRITE_TYPE_MASK)
|
||||
|
||||
struct bch_fs {
|
||||
struct closure cl;
|
||||
|
||||
|
@ -631,7 +631,6 @@ out:
|
||||
b->flags = 0;
|
||||
b->written = 0;
|
||||
b->nsets = 0;
|
||||
b->write_type = 0;
|
||||
b->sib_u64s[0] = 0;
|
||||
b->sib_u64s[1] = 0;
|
||||
b->whiteout_u64s = 0;
|
||||
|
@ -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);
|
||||
|
@ -77,7 +77,6 @@ struct btree {
|
||||
u8 nsets;
|
||||
u8 nr_key_bits;
|
||||
u16 version_ondisk;
|
||||
u8 write_type;
|
||||
|
||||
struct bkey_format format;
|
||||
|
||||
@ -445,6 +444,23 @@ struct btree_trans {
|
||||
struct replicas_delta_list *fs_usage_deltas;
|
||||
};
|
||||
|
||||
#define BCH_BTREE_WRITE_TYPES() \
|
||||
x(initial, 0) \
|
||||
x(init_next_bset, 1) \
|
||||
x(cache_reclaim, 2) \
|
||||
x(journal_reclaim, 3) \
|
||||
x(interior, 4)
|
||||
|
||||
enum btree_write_type {
|
||||
#define x(t, n) BTREE_WRITE_##t,
|
||||
BCH_BTREE_WRITE_TYPES()
|
||||
#undef x
|
||||
BTREE_WRITE_TYPE_NR,
|
||||
};
|
||||
|
||||
#define BTREE_WRITE_TYPE_MASK (roundup_pow_of_two(BTREE_WRITE_TYPE_NR) - 1)
|
||||
#define BTREE_WRITE_TYPE_BITS ilog2(roundup_pow_of_two(BTREE_WRITE_TYPE_NR))
|
||||
|
||||
#define BTREE_FLAGS() \
|
||||
x(read_in_flight) \
|
||||
x(read_error) \
|
||||
@ -464,6 +480,8 @@ struct btree_trans {
|
||||
x(never_write)
|
||||
|
||||
enum btree_flags {
|
||||
/* First bits for btree node write type */
|
||||
BTREE_NODE_FLAGS_START = BTREE_WRITE_TYPE_BITS - 1,
|
||||
#define x(flag) BTREE_NODE_##flag,
|
||||
BTREE_FLAGS()
|
||||
#undef x
|
||||
|
@ -1257,6 +1257,7 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as,
|
||||
struct bch_fs *c = as->c;
|
||||
struct bkey_packed *k;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
unsigned long old, new, v;
|
||||
|
||||
BUG_ON(insert->k.type == KEY_TYPE_btree_ptr_v2 &&
|
||||
!btree_ptr_sectors_written(insert));
|
||||
@ -1294,8 +1295,15 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as,
|
||||
|
||||
bch2_btree_bset_insert_key(trans, path, b, node_iter, insert);
|
||||
set_btree_node_dirty_acct(c, b);
|
||||
set_btree_node_need_write(b);
|
||||
b->write_type = BTREE_WRITE_interior;
|
||||
|
||||
v = READ_ONCE(b->flags);
|
||||
do {
|
||||
old = new = v;
|
||||
|
||||
new &= ~BTREE_WRITE_TYPE_MASK;
|
||||
new |= BTREE_WRITE_interior;
|
||||
new |= 1 << BTREE_NODE_need_write;
|
||||
} while ((v = cmpxchg(&b->flags, old, new)) != old);
|
||||
|
||||
printbuf_exit(&buf);
|
||||
}
|
||||
|
@ -178,11 +178,11 @@ static int __btree_node_flush(struct journal *j, struct journal_entry_pin *pin,
|
||||
w->journal.seq != seq)
|
||||
break;
|
||||
|
||||
new &= ~BTREE_WRITE_TYPE_MASK;
|
||||
new |= BTREE_WRITE_journal_reclaim;
|
||||
new |= 1 << BTREE_NODE_need_write;
|
||||
} while ((v = cmpxchg(&b->flags, old, new)) != old);
|
||||
|
||||
b->write_type = BTREE_WRITE_journal_reclaim;
|
||||
|
||||
btree_node_write_if_need(c, b, SIX_LOCK_read);
|
||||
six_unlock_read(&b->c.lock);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user