diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-02-17 21:04:46 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:09:53 -0400 |
commit | af0ee5bcf3012be753ab15ce9c27971e5b34bd74 (patch) | |
tree | 6f019d4385ef81763211657469f456f9ac63263b | |
parent | 6623c0fcdffe22db466ec38c5f9f4b3a44c33003 (diff) | |
download | lwn-af0ee5bcf3012be753ab15ce9c27971e5b34bd74.tar.gz lwn-af0ee5bcf3012be753ab15ce9c27971e5b34bd74.zip |
bcachefs: Don't block on ec_stripe_head_lock with btree locks held
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/ec.c | 24 |
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) { |