summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2020-12-15 12:38:17 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2020-12-17 14:08:26 -0500
commit34881783a2bdfa44308d9e2d06b0d79b7453b547 (patch)
tree6c2acd04718043d1cc50db78f235e7d923ba2c16
parent40357233ec13b80a8eb051e92f5220bdc30871d7 (diff)
bcachefs: Change allocations for ec stripes to blocking
XXX It's not guaranteed that these allocations will ever succeed, we can currently get stuck - especially if devices are different sizes. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/alloc_foreground.c42
-rw-r--r--fs/bcachefs/ec.c23
-rw-r--r--fs/bcachefs/ec.h4
3 files changed, 38 insertions, 31 deletions
diff --git a/fs/bcachefs/alloc_foreground.c b/fs/bcachefs/alloc_foreground.c
index 7a92e3d53254..0c5c69d643f6 100644
--- a/fs/bcachefs/alloc_foreground.c
+++ b/fs/bcachefs/alloc_foreground.c
@@ -458,16 +458,18 @@ bch2_bucket_alloc_set(struct bch_fs *c,
* it's to a device we don't want:
*/
-static void bucket_alloc_from_stripe(struct bch_fs *c,
- struct open_buckets *ptrs,
- struct write_point *wp,
- struct bch_devs_mask *devs_may_alloc,
- u16 target,
- unsigned erasure_code,
- unsigned nr_replicas,
- unsigned *nr_effective,
- bool *have_cache,
- unsigned flags)
+static enum bucket_alloc_ret
+bucket_alloc_from_stripe(struct bch_fs *c,
+ struct open_buckets *ptrs,
+ struct write_point *wp,
+ struct bch_devs_mask *devs_may_alloc,
+ u16 target,
+ unsigned erasure_code,
+ unsigned nr_replicas,
+ unsigned *nr_effective,
+ bool *have_cache,
+ unsigned flags,
+ struct closure *cl)
{
struct dev_alloc_list devs_sorted;
struct ec_stripe_head *h;
@@ -476,17 +478,19 @@ static void bucket_alloc_from_stripe(struct bch_fs *c,
unsigned i, ec_idx;
if (!erasure_code)
- return;
+ return 0;
if (nr_replicas < 2)
- return;
+ return 0;
if (ec_open_bucket(c, ptrs))
- return;
+ return 0;
- h = bch2_ec_stripe_head_get(c, target, 0, nr_replicas - 1);
+ h = bch2_ec_stripe_head_get(c, target, 0, nr_replicas - 1, cl);
+ if (IS_ERR(h))
+ return -PTR_ERR(h);
if (!h)
- return;
+ return 0;
devs_sorted = bch2_dev_alloc_list(c, &wp->stripe, devs_may_alloc);
@@ -508,6 +512,7 @@ got_bucket:
atomic_inc(&h->s->pin);
out_put_head:
bch2_ec_stripe_head_put(c, h);
+ return 0;
}
/* Sector allocator */
@@ -585,10 +590,13 @@ open_bucket_add_buckets(struct bch_fs *c,
}
if (!ec_open_bucket(c, ptrs)) {
- bucket_alloc_from_stripe(c, ptrs, wp, &devs,
+ ret = bucket_alloc_from_stripe(c, ptrs, wp, &devs,
target, erasure_code,
nr_replicas, nr_effective,
- have_cache, flags);
+ have_cache, flags, _cl);
+ if (ret == FREELIST_EMPTY ||
+ ret == OPEN_BUCKETS_EMPTY)
+ return ret;
if (*nr_effective >= nr_replicas)
return 0;
}
diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c
index beb91d33a992..903b81744c8f 100644
--- a/fs/bcachefs/ec.c
+++ b/fs/bcachefs/ec.c
@@ -1229,10 +1229,9 @@ found:
return h;
}
-/*
- * XXX: use a higher watermark for allocating open buckets here:
- */
-static int new_stripe_alloc_buckets(struct bch_fs *c, struct ec_stripe_head *h)
+static enum bucket_alloc_ret
+new_stripe_alloc_buckets(struct bch_fs *c, struct ec_stripe_head *h,
+ struct closure *cl)
{
struct bch_devs_mask devs;
struct open_bucket *ob;
@@ -1240,7 +1239,7 @@ static int new_stripe_alloc_buckets(struct bch_fs *c, struct ec_stripe_head *h)
min_t(unsigned, h->nr_active_devs,
BCH_BKEY_PTRS_MAX) - h->redundancy;
bool have_cache = true;
- int ret = 0;
+ enum bucket_alloc_ret ret = ALLOC_SUCCESS;
devs = h->devs;
@@ -1271,7 +1270,7 @@ static int new_stripe_alloc_buckets(struct bch_fs *c, struct ec_stripe_head *h)
&have_cache,
RESERVE_NONE,
0,
- NULL);
+ cl);
if (ret)
goto err;
}
@@ -1287,7 +1286,7 @@ static int new_stripe_alloc_buckets(struct bch_fs *c, struct ec_stripe_head *h)
&have_cache,
RESERVE_NONE,
0,
- NULL);
+ cl);
if (ret)
goto err;
}
@@ -1353,7 +1352,8 @@ static int get_stripe_key(struct bch_fs *c, u64 idx, struct ec_stripe_buf *strip
struct ec_stripe_head *bch2_ec_stripe_head_get(struct bch_fs *c,
unsigned target,
unsigned algo,
- unsigned redundancy)
+ unsigned redundancy,
+ struct closure *cl)
{
struct ec_stripe_head *h;
struct open_bucket *ob;
@@ -1422,14 +1422,13 @@ struct ec_stripe_head *bch2_ec_stripe_head_get(struct bch_fs *c,
bch2_ec_stripe_head_put(c, h);
h = NULL;
goto out;
-
}
-
}
- if (new_stripe_alloc_buckets(c, h)) {
+ ret = new_stripe_alloc_buckets(c, h, cl);
+ if (ret) {
bch2_ec_stripe_head_put(c, h);
- h = NULL;
+ h = ERR_PTR(-ret);
goto out;
}
diff --git a/fs/bcachefs/ec.h b/fs/bcachefs/ec.h
index 1d4aad50db4d..3f1999bae6d4 100644
--- a/fs/bcachefs/ec.h
+++ b/fs/bcachefs/ec.h
@@ -146,8 +146,8 @@ void bch2_ec_bucket_cancel(struct bch_fs *, struct open_bucket *);
int bch2_ec_stripe_new_alloc(struct bch_fs *, struct ec_stripe_head *);
void bch2_ec_stripe_head_put(struct bch_fs *, struct ec_stripe_head *);
-struct ec_stripe_head *bch2_ec_stripe_head_get(struct bch_fs *, unsigned,
- unsigned, unsigned);
+struct ec_stripe_head *bch2_ec_stripe_head_get(struct bch_fs *,
+ unsigned, unsigned, unsigned, struct closure *);
void bch2_stripes_heap_update(struct bch_fs *, struct stripe *, size_t);
void bch2_stripes_heap_del(struct bch_fs *, struct stripe *, size_t);