mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-14 06:30:20 -04:00
bcachefs: Don't require alloc btree to be updated before buckets are used
This is to break a circular dependency in the shutdown path. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
committed by
Kent Overstreet
parent
beb6db68a5
commit
baeed3c3c0
@@ -843,7 +843,7 @@ static int bch2_invalidate_one_bucket2(struct btree_trans *trans,
|
||||
struct bkey_s_c k;
|
||||
bool invalidating_cached_data;
|
||||
size_t b;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(!ca->alloc_heap.used ||
|
||||
!ca->alloc_heap.data[0].nr);
|
||||
@@ -857,11 +857,18 @@ static int bch2_invalidate_one_bucket2(struct btree_trans *trans,
|
||||
|
||||
BUG_ON(!fifo_push(&ca->free_inc, b));
|
||||
|
||||
g = bucket(ca, b);
|
||||
m = READ_ONCE(g->mark);
|
||||
|
||||
bch2_mark_alloc_bucket(c, ca, b, true, gc_pos_alloc(c, NULL), 0);
|
||||
|
||||
spin_unlock(&c->freelist_lock);
|
||||
percpu_up_read(&c->mark_lock);
|
||||
|
||||
invalidating_cached_data = m.cached_sectors != 0;
|
||||
if (!invalidating_cached_data)
|
||||
goto out;
|
||||
|
||||
BUG_ON(BKEY_ALLOC_VAL_U64s_MAX > 8);
|
||||
|
||||
bch2_btree_iter_set_pos(iter, POS(ca->dev_idx, b));
|
||||
@@ -915,7 +922,7 @@ static int bch2_invalidate_one_bucket2(struct btree_trans *trans,
|
||||
flags);
|
||||
if (ret == -EINTR)
|
||||
goto retry;
|
||||
|
||||
out:
|
||||
if (!ret) {
|
||||
/* remove from alloc_heap: */
|
||||
struct alloc_heap_entry e, *top = ca->alloc_heap.data;
|
||||
|
||||
@@ -1457,11 +1457,13 @@ static int bch2_trans_mark_pointer(struct btree_trans *trans,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!ret && unlikely(!test_bit(BCH_FS_ALLOC_WRITTEN, &c->flags))) {
|
||||
if (k.k->type != KEY_TYPE_alloc ||
|
||||
(!ret && unlikely(!test_bit(BCH_FS_ALLOC_WRITTEN, &c->flags)))) {
|
||||
/*
|
||||
* During journal replay, and if gc repairs alloc info at
|
||||
* runtime, the alloc info in the btree might not be up to date
|
||||
* yet - so, trust the in memory mark:
|
||||
* yet - so, trust the in memory mark - unless we're already
|
||||
* updating that key:
|
||||
*/
|
||||
struct bucket *g;
|
||||
struct bucket_mark m;
|
||||
@@ -1472,22 +1474,39 @@ static int bch2_trans_mark_pointer(struct btree_trans *trans,
|
||||
u = alloc_mem_to_key(g, m);
|
||||
percpu_up_read(&c->mark_lock);
|
||||
} else {
|
||||
/*
|
||||
* Unless we're already updating that key:
|
||||
*/
|
||||
if (k.k->type != KEY_TYPE_alloc) {
|
||||
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
|
||||
"pointer to nonexistent bucket %llu:%llu",
|
||||
iter->pos.inode, iter->pos.offset);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
u = bch2_alloc_unpack(k);
|
||||
}
|
||||
|
||||
if (gen_after(u.gen, p.ptr.gen)) {
|
||||
if (u.gen != p.ptr.gen) {
|
||||
ret = 1;
|
||||
|
||||
if (gen_after(p.ptr.gen, u.gen)) {
|
||||
bch2_fs_inconsistent(c,
|
||||
"bucket %llu:%llu gen %u data type %s: ptr gen %u newer than bucket gen",
|
||||
iter->pos.inode, iter->pos.offset, u.gen,
|
||||
bch2_data_types[u.data_type ?: data_type],
|
||||
p.ptr.gen);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
if (gen_cmp(u.gen, p.ptr.gen) >= 96U) {
|
||||
bch2_fs_inconsistent(c,
|
||||
"bucket %llu:%llu gen %u data type %s: ptr gen %u too stale",
|
||||
iter->pos.inode, iter->pos.offset, u.gen,
|
||||
bch2_data_types[u.data_type ?: data_type],
|
||||
p.ptr.gen);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
if (!p.ptr.cached) {
|
||||
bch2_fs_inconsistent(c,
|
||||
"bucket %llu:%llu gen %u data type %s: stale dirty ptr (gen %u)",
|
||||
iter->pos.inode, iter->pos.offset, u.gen,
|
||||
bch2_data_types[u.data_type ?: data_type],
|
||||
p.ptr.gen);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user