Skip to content

Commit

Permalink
bcachefs: Don't recurse in check_discard_freespace_key
Browse files Browse the repository at this point in the history
When calling check_discard_freeespace_key from the allocator, we can't
repair without recursing - run it asynchronously instead.

Signed-off-by: Kent Overstreet <[email protected]>
  • Loading branch information
Kent Overstreet committed Nov 29, 2024
1 parent 2d5a193 commit 173f06e
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 10 deletions.
72 changes: 64 additions & 8 deletions fs/bcachefs/alloc_background.c
Original file line number Diff line number Diff line change
Expand Up @@ -1338,7 +1338,40 @@ int bch2_check_alloc_hole_bucket_gens(struct btree_trans *trans,
return ret;
}

int bch2_check_discard_freespace_key(struct btree_trans *trans, struct btree_iter *iter, u8 *gen)
struct check_discard_freespace_key_async {
struct work_struct work;
struct bch_fs *c;
struct bbpos pos;
};

static int bch2_recheck_discard_freespace_key(struct btree_trans *trans, struct bbpos pos)
{
struct btree_iter iter;
struct bkey_s_c k = bch2_bkey_get_iter(trans, &iter, pos.btree, pos.pos, 0);
int ret = bkey_err(k);
if (ret)
return ret;

u8 gen;
ret = k.k->type != KEY_TYPE_set
? bch2_check_discard_freespace_key(trans, &iter, &gen, false)
: 0;
bch2_trans_iter_exit(trans, &iter);
return ret;
}

static void check_discard_freespace_key_work(struct work_struct *work)
{
struct check_discard_freespace_key_async *w =
container_of(work, struct check_discard_freespace_key_async, work);

bch2_trans_do(w->c, bch2_recheck_discard_freespace_key(trans, w->pos));
bch2_write_ref_put(w->c, BCH_WRITE_REF_check_discard_freespace_key);
kfree(w);
}

int bch2_check_discard_freespace_key(struct btree_trans *trans, struct btree_iter *iter, u8 *gen,
bool async_repair)
{
struct bch_fs *c = trans->c;
enum bch_data_type state = iter->btree_id == BTREE_ID_need_discard
Expand All @@ -1351,7 +1384,8 @@ int bch2_check_discard_freespace_key(struct btree_trans *trans, struct btree_ite
u64 genbits = iter->pos.offset & (~0ULL << 56);

struct btree_iter alloc_iter;
struct bkey_s_c alloc_k = bch2_bkey_get_iter(trans, &alloc_iter, BTREE_ID_alloc, bucket, BTREE_ITER_cached);
struct bkey_s_c alloc_k = bch2_bkey_get_iter(trans, &alloc_iter,
BTREE_ID_alloc, bucket, BTREE_ITER_cached);
int ret = bkey_err(alloc_k);
if (ret)
return ret;
Expand Down Expand Up @@ -1392,17 +1426,39 @@ int bch2_check_discard_freespace_key(struct btree_trans *trans, struct btree_ite
printbuf_exit(&buf);
return ret;
delete:
ret = bch2_btree_bit_mod_iter(trans, iter, false) ?:
bch2_trans_commit(trans, NULL, NULL,
BCH_TRANS_COMMIT_no_enospc) ?:
-BCH_ERR_transaction_restart_commit;
goto out;
if (!async_repair) {
ret = bch2_btree_bit_mod_iter(trans, iter, false) ?:
bch2_trans_commit(trans, NULL, NULL,
BCH_TRANS_COMMIT_no_enospc) ?:
-BCH_ERR_transaction_restart_commit;
goto out;
} else {
/*
* We can't repair here when called from the allocator path: the
* commit will recurse back into the allocator
*/
struct check_discard_freespace_key_async *w =
kzalloc(sizeof(*w), GFP_KERNEL);
if (!w)
goto out;

if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_check_discard_freespace_key)) {
kfree(w);
goto out;
}

INIT_WORK(&w->work, check_discard_freespace_key_work);
w->c = c;
w->pos = BBPOS(iter->btree_id, iter->pos);
queue_work(c->write_ref_wq, &w->work);
goto out;
}
}

static int bch2_check_discard_freespace_key_fsck(struct btree_trans *trans, struct btree_iter *iter)
{
u8 gen;
int ret = bch2_check_discard_freespace_key(trans, iter, &gen);
int ret = bch2_check_discard_freespace_key(trans, iter, &gen, false);
return ret < 0 ? ret : 0;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/bcachefs/alloc_background.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ int bch2_trigger_alloc(struct btree_trans *, enum btree_id, unsigned,
struct bkey_s_c, struct bkey_s,
enum btree_iter_update_trigger_flags);

int bch2_check_discard_freespace_key(struct btree_trans *, struct btree_iter *, u8 *);
int bch2_check_discard_freespace_key(struct btree_trans *, struct btree_iter *, u8 *, bool);
int bch2_check_alloc_info(struct bch_fs *);
int bch2_check_alloc_to_lru_refs(struct bch_fs *);
void bch2_dev_do_discards(struct bch_dev *);
Expand Down
2 changes: 1 addition & 1 deletion fs/bcachefs/alloc_foreground.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bc
u64 b = freespace_iter->pos.offset & ~(~0ULL << 56);
u8 gen;

int ret = bch2_check_discard_freespace_key(trans, freespace_iter, &gen);
int ret = bch2_check_discard_freespace_key(trans, freespace_iter, &gen, true);
if (ret < 0)
return ERR_PTR(ret);
if (ret)
Expand Down
1 change: 1 addition & 0 deletions fs/bcachefs/bcachefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ struct btree_trans_buf {
x(dio_write) \
x(discard) \
x(discard_fast) \
x(check_discard_freespace_key) \
x(invalidate) \
x(delete_dead_snapshots) \
x(gc_gens) \
Expand Down

0 comments on commit 173f06e

Please sign in to comment.