From: Kent Overstreet Date: Mon, 20 Jan 2025 01:34:57 +0000 (-0500) Subject: bcachefs: Don't self-heal if a data update is already rewriting X-Git-Tag: v6.15-rc1~146^2~153 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7b1d6551060066a1fed2a1f83485b0ea37ca3001;p=thirdparty%2Fkernel%2Flinux.git bcachefs: Don't self-heal if a data update is already rewriting Signed-off-by: Kent Overstreet --- diff --git a/fs/bcachefs/io_read.c b/fs/bcachefs/io_read.c index 15494aba4547b..bb5d1de25aa19 100644 --- a/fs/bcachefs/io_read.c +++ b/fs/bcachefs/io_read.c @@ -97,6 +97,26 @@ static inline bool have_io_error(struct bch_io_failures *failed) return failed && failed->nr; } +static bool ptr_being_rewritten(struct bch_read_bio *orig, + unsigned dev, + unsigned flags) +{ + if (!(flags & BCH_READ_data_update)) + return false; + + struct data_update *u = container_of(orig, struct data_update, rbio); + struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(bkey_i_to_s_c(u->k.k)); + unsigned i = 0; + bkey_for_each_ptr(ptrs, ptr) { + if (ptr->dev == dev && + u->data_opts.rewrite_ptrs & BIT(i)) + return true; + i++; + } + + return false; +} + static inline int should_promote(struct bch_fs *c, struct bkey_s_c k, struct bpos pos, struct bch_io_opts opts, @@ -173,30 +193,13 @@ static struct bch_read_bio *__promote_alloc(struct btree_trans *trans, struct bpos pos, struct extent_ptr_decoded *pick, unsigned sectors, + unsigned flags, struct bch_read_bio *orig, struct bch_io_failures *failed) { struct bch_fs *c = trans->c; int ret; - if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_promote)) - return ERR_PTR(-BCH_ERR_nopromote_no_writes); - - struct promote_op *op = kzalloc(sizeof(*op), GFP_KERNEL); - if (!op) { - ret = -BCH_ERR_nopromote_enomem; - goto err_put; - } - - op->start_time = local_clock(); - op->pos = pos; - - if (rhashtable_lookup_insert_fast(&c->promote_table, &op->hash, - bch_promote_params)) { - ret = -BCH_ERR_nopromote_in_flight; - goto err; - } - struct data_update_opts update_opts = { .write_flags = BCH_WRITE_alloc_nowait }; if (!have_io_error(failed)) { @@ -210,10 +213,32 @@ static struct bch_read_bio *__promote_alloc(struct btree_trans *trans, struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k); unsigned ptr_bit = 1; bkey_for_each_ptr(ptrs, ptr) { - if (bch2_dev_io_failures(failed, ptr->dev)) + if (bch2_dev_io_failures(failed, ptr->dev) && + !ptr_being_rewritten(orig, ptr->dev, flags)) update_opts.rewrite_ptrs |= ptr_bit; ptr_bit <<= 1; } + + if (!update_opts.rewrite_ptrs) + return NULL; + } + + if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_promote)) + return ERR_PTR(-BCH_ERR_nopromote_no_writes); + + struct promote_op *op = kzalloc(sizeof(*op), GFP_KERNEL); + if (!op) { + ret = -BCH_ERR_nopromote_enomem; + goto err_put; + } + + op->start_time = local_clock(); + op->pos = pos; + + if (rhashtable_lookup_insert_fast(&c->promote_table, &op->hash, + bch_promote_params)) { + ret = -BCH_ERR_nopromote_in_flight; + goto err; } ret = bch2_data_update_init(trans, NULL, NULL, &op->write, @@ -283,7 +308,10 @@ static struct bch_read_bio *promote_alloc(struct btree_trans *trans, k.k->type == KEY_TYPE_reflink_v ? BTREE_ID_reflink : BTREE_ID_extents, - k, pos, pick, sectors, orig, failed); + k, pos, pick, sectors, flags, orig, failed); + if (!promote) + return NULL; + ret = PTR_ERR_OR_ZERO(promote); if (ret) goto nopromote;