summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Hill <daniel@gluo.nz>2023-01-06 21:11:07 +1300
committerKent Overstreet <kent.overstreet@linux.dev>2023-03-13 11:34:49 -0400
commitab30ea8e044beeab202e54bf67f16b4cef849ed1 (patch)
tree63932cf3e3fcb44c2b1de0f2bf4813835d1cd5a3
parent05283fec05a4b01fb0befacfdfc1097d9219616f (diff)
bcachefs: don't block reads if we're promoting
The promote path calls data_update_init() and now that we take locks here, there's potential for promote to block our read path, just error when we can't take the lock instead of blocking. Signed-off-by: Daniel Hill <daniel@gluo.nz>
-rw-r--r--fs/bcachefs/data_update.c26
-rw-r--r--fs/bcachefs/errcode.h1
-rw-r--r--fs/bcachefs/io.c7
3 files changed, 25 insertions, 9 deletions
diff --git a/fs/bcachefs/data_update.c b/fs/bcachefs/data_update.c
index d44fc1a3d622..9df958b43dfe 100644
--- a/fs/bcachefs/data_update.c
+++ b/fs/bcachefs/data_update.c
@@ -412,6 +412,7 @@ int bch2_data_update_init(struct btree_trans *trans,
const union bch_extent_entry *entry;
struct extent_ptr_decoded p;
unsigned i, reserve_sectors = k.k->size * data_opts.extra_replicas;
+ unsigned int ptrs_locked = 0;
int ret;
bch2_bkey_buf_init(&m->k);
@@ -437,6 +438,8 @@ int bch2_data_update_init(struct btree_trans *trans,
i = 0;
bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
+ bool locked;
+
if (((1U << i) & m->data_opts.rewrite_ptrs) &&
p.ptr.cached)
BUG();
@@ -462,11 +465,7 @@ int bch2_data_update_init(struct btree_trans *trans,
if (p.crc.compression_type == BCH_COMPRESSION_TYPE_incompressible)
m->op.incompressible = true;
- i++;
-
if (ctxt) {
- bool locked;
-
move_ctxt_wait_event(ctxt, trans,
(locked = bch2_bucket_nocow_trylock(&c->nocow_locks,
PTR_BUCKET_POS(c, &p.ptr), 0)) ||
@@ -476,9 +475,14 @@ int bch2_data_update_init(struct btree_trans *trans,
bch2_bucket_nocow_lock(&c->nocow_locks,
PTR_BUCKET_POS(c, &p.ptr), 0);
} else {
- bch2_bucket_nocow_lock(&c->nocow_locks,
- PTR_BUCKET_POS(c, &p.ptr), 0);
+ if (!bch2_bucket_nocow_trylock(&c->nocow_locks,
+ PTR_BUCKET_POS(c, &p.ptr), 0)) {
+ ret = -BCH_ERR_nocow_lock_blocked;
+ goto err;
+ }
}
+ ptrs_locked |= (1U << i);
+ i++;
}
if (reserve_sectors) {
@@ -500,9 +504,13 @@ int bch2_data_update_init(struct btree_trans *trans,
return -BCH_ERR_unwritten_extent_update;
return 0;
err:
- bkey_for_each_ptr_decode(k.k, ptrs, p, entry)
- bch2_bucket_nocow_unlock(&c->nocow_locks,
- PTR_BUCKET_POS(c, &p.ptr), 0);
+ i = 0;
+ bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
+ if ((1U << i) & ptrs_locked)
+ bch2_bucket_nocow_unlock(&c->nocow_locks,
+ PTR_BUCKET_POS(c, &p.ptr), 0);
+ i++;
+ }
bch2_bkey_buf_exit(&m->k, c);
bch2_bio_free_pages_pool(c, &m->op.wbio.bio);
diff --git a/fs/bcachefs/errcode.h b/fs/bcachefs/errcode.h
index 57f1d0a6a490..6129af6129c3 100644
--- a/fs/bcachefs/errcode.h
+++ b/fs/bcachefs/errcode.h
@@ -120,6 +120,7 @@
x(BCH_ERR_invalid_sb, invalid_sb_clean) \
x(BCH_ERR_invalid_sb, invalid_sb_quota) \
x(BCH_ERR_invalid, invalid_bkey) \
+ x(BCH_ERR_operation_blocked, nocow_lock_blocked) \
enum bch_errcode {
BCH_ERR_START = 2048,
diff --git a/fs/bcachefs/io.c b/fs/bcachefs/io.c
index 27159c646043..64925db22cdc 100644
--- a/fs/bcachefs/io.c
+++ b/fs/bcachefs/io.c
@@ -2024,6 +2024,13 @@ static struct promote_op *__promote_alloc(struct btree_trans *trans,
.write_flags = BCH_WRITE_ALLOC_NOWAIT|BCH_WRITE_CACHED,
},
btree_id, k);
+ if (ret == -BCH_ERR_nocow_lock_blocked) {
+ ret = rhashtable_remove_fast(&c->promote_table, &op->hash,
+ bch_promote_params);
+ BUG_ON(ret);
+ goto err;
+ }
+
BUG_ON(ret);
op->write.op.end_io = promote_done;