summaryrefslogtreecommitdiff
path: root/fs/bcachefs/ec.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/bcachefs/ec.c')
-rw-r--r--fs/bcachefs/ec.c38
1 files changed, 24 insertions, 14 deletions
diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c
index 687c3ba98095..71956ee86a9c 100644
--- a/fs/bcachefs/ec.c
+++ b/fs/bcachefs/ec.c
@@ -1720,8 +1720,7 @@ err:
static int new_stripe_alloc_buckets(struct btree_trans *trans,
struct alloc_request *req,
- struct ec_stripe_head *h, struct ec_stripe_new *s,
- struct closure *cl)
+ struct ec_stripe_head *h, struct ec_stripe_new *s)
{
struct bch_fs *c = trans->c;
struct open_bucket *ob;
@@ -1771,7 +1770,7 @@ static int new_stripe_alloc_buckets(struct btree_trans *trans,
req->nr_effective = nr_have_parity;
req->data_type = BCH_DATA_parity;
- ret = bch2_bucket_alloc_set_trans(trans, req, &h->parity_stripe, cl);
+ ret = bch2_bucket_alloc_set_trans(trans, req, &h->parity_stripe);
open_bucket_for_each(c, &req->ptrs, ob, i) {
j = find_next_zero_bit(s->blocks_gotten,
@@ -1794,7 +1793,7 @@ static int new_stripe_alloc_buckets(struct btree_trans *trans,
req->nr_effective = nr_have_data;
req->data_type = BCH_DATA_user;
- ret = bch2_bucket_alloc_set_trans(trans, req, &h->block_stripe, cl);
+ ret = bch2_bucket_alloc_set_trans(trans, req, &h->block_stripe);
open_bucket_for_each(c, &req->ptrs, ob, i) {
j = find_next_zero_bit(s->blocks_gotten,
@@ -1926,7 +1925,7 @@ static int __bch2_ec_stripe_head_reuse(struct btree_trans *trans, struct ec_stri
}
bch2_trans_iter_exit(trans, &lru_iter);
if (!ret)
- ret = bch_err_throw(c, stripe_alloc_blocked);
+ return bch_err_throw(c, stripe_alloc_blocked);
if (ret == 1)
ret = 0;
if (ret)
@@ -1998,8 +1997,7 @@ err:
struct ec_stripe_head *bch2_ec_stripe_head_get(struct btree_trans *trans,
struct alloc_request *req,
- unsigned algo,
- struct closure *cl)
+ unsigned algo)
{
struct bch_fs *c = trans->c;
unsigned redundancy = req->nr_replicas - 1;
@@ -2041,12 +2039,18 @@ struct ec_stripe_head *bch2_ec_stripe_head_get(struct btree_trans *trans,
if (s->have_existing_stripe)
goto alloc_existing;
+
/* First, try to allocate a full stripe: */
enum bch_watermark saved_watermark = BCH_WATERMARK_stripe;
- swap(req->watermark, saved_watermark);
- ret = new_stripe_alloc_buckets(trans, req, h, s, NULL) ?:
+ unsigned saved_flags = req->flags | BCH_WRITE_alloc_nowait;
+ swap(req->watermark, saved_watermark);
+ swap(req->flags, saved_flags);
+
+ ret = new_stripe_alloc_buckets(trans, req, h, s) ?:
__bch2_ec_stripe_head_reserve(trans, h, s);
- swap(req->watermark, saved_watermark);
+
+ swap(req->watermark, saved_watermark);
+ swap(req->flags, saved_flags);
if (!ret)
goto allocate_buf;
@@ -2062,19 +2066,25 @@ struct ec_stripe_head *bch2_ec_stripe_head_get(struct btree_trans *trans,
ret = __bch2_ec_stripe_head_reuse(trans, h, s);
if (!ret)
break;
- if (waiting || !cl || ret != -BCH_ERR_stripe_alloc_blocked)
+ if (waiting ||
+ (req->flags & BCH_WRITE_alloc_nowait) ||
+ ret != -BCH_ERR_stripe_alloc_blocked)
goto err;
if (req->watermark == BCH_WATERMARK_copygc) {
- ret = new_stripe_alloc_buckets(trans, req, h, s, NULL) ?:
+ /* Don't self-deadlock copygc */
+ swap(req->flags, saved_flags);
+ ret = new_stripe_alloc_buckets(trans, req, h, s) ?:
__bch2_ec_stripe_head_reserve(trans, h, s);
+ swap(req->flags, saved_flags);
+
if (ret)
goto err;
goto allocate_buf;
}
/* XXX freelist_wait? */
- closure_wait(&c->freelist_wait, cl);
+ closure_wait(&c->freelist_wait, req->cl);
waiting = true;
}
@@ -2085,7 +2095,7 @@ alloc_existing:
* Retry allocating buckets, with the watermark for this
* particular write:
*/
- ret = new_stripe_alloc_buckets(trans, req, h, s, cl);
+ ret = new_stripe_alloc_buckets(trans, req, h, s);
if (ret)
goto err;