aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorGravatar Kent Overstreet <kent.overstreet@linux.dev> 2023-02-17 21:04:46 -0500
committerGravatar Kent Overstreet <kent.overstreet@linux.dev> 2023-10-22 17:09:53 -0400
commitaf0ee5bcf3012be753ab15ce9c27971e5b34bd74 (patch)
tree6f019d4385ef81763211657469f456f9ac63263b /fs
parentbcachefs: Add an assertion for using multiple btree_trans (diff)
downloadlinux-af0ee5bcf3012be753ab15ce9c27971e5b34bd74.tar.gz
linux-af0ee5bcf3012be753ab15ce9c27971e5b34bd74.tar.bz2
linux-af0ee5bcf3012be753ab15ce9c27971e5b34bd74.zip
bcachefs: Don't block on ec_stripe_head_lock with btree locks held
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs')
-rw-r--r--fs/bcachefs/ec.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c
index ca3e4a18e28a..236e1bef5f02 100644
--- a/fs/bcachefs/ec.c
+++ b/fs/bcachefs/ec.c
@@ -1267,18 +1267,30 @@ void bch2_ec_stripe_head_put(struct bch_fs *c, struct ec_stripe_head *h)
mutex_unlock(&h->lock);
}
-struct ec_stripe_head *__bch2_ec_stripe_head_get(struct bch_fs *c,
+struct ec_stripe_head *__bch2_ec_stripe_head_get(struct btree_trans *trans,
unsigned target,
unsigned algo,
unsigned redundancy,
bool copygc)
{
+ struct bch_fs *c = trans->c;
struct ec_stripe_head *h;
+ int ret;
if (!redundancy)
return NULL;
- mutex_lock(&c->ec_stripe_head_lock);
+ if (!mutex_trylock(&c->ec_stripe_head_lock)) {
+ bch2_trans_unlock(trans);
+ mutex_lock(&c->ec_stripe_head_lock);
+
+ ret = bch2_trans_relock(trans);
+ if (ret) {
+ mutex_unlock(&c->ec_stripe_head_lock);
+ return ERR_PTR(ret);
+ }
+ }
+
list_for_each_entry(h, &c->ec_stripe_head_list, list)
if (h->target == target &&
h->algo == algo &&
@@ -1477,11 +1489,11 @@ struct ec_stripe_head *bch2_ec_stripe_head_get(struct btree_trans *trans,
int ret;
bool needs_stripe_new;
- h = __bch2_ec_stripe_head_get(c, target, algo, redundancy, copygc);
- if (!h) {
+ h = __bch2_ec_stripe_head_get(trans, target, algo, redundancy, copygc);
+ if (!h)
bch_err(c, "no stripe head");
- return NULL;
- }
+ if (IS_ERR_OR_NULL(h))
+ return h;
needs_stripe_new = !h->s;
if (needs_stripe_new) {