summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2025-01-19 20:34:57 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2025-02-07 14:49:49 -0500
commitfe53ea84d0548faa9a66badcddd90bc4148c60f5 (patch)
treeba49625e5065ece61ae6b0bb29b4f10e658aa12e
parentd1a34af1237066612d07898abf1f2c2868ca2ed5 (diff)
bcachefs: Don't self-heal if a data update is already rewriting
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/io_read.c68
1 files changed, 48 insertions, 20 deletions
diff --git a/fs/bcachefs/io_read.c b/fs/bcachefs/io_read.c
index b0495f7a0782..9353fda974b3 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;