bcachefs: Change allocations for ec stripes to blocking
authorKent Overstreet <kent.overstreet@gmail.com>
Tue, 15 Dec 2020 17:38:17 +0000 (12:38 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:50 +0000 (17:08 -0400)
We don't want writes to not get erasure coded just because the allocator
temporarily wasn't keeping up.

However, it's not guaranteed that these allocations will ever succeed,
we can currently get stuck - especially if devices are different sizes -
we still have work to do in this area.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/alloc_foreground.c
fs/bcachefs/ec.c
fs/bcachefs/ec.h

index 1ea8ee99956b5620f1a6ea8257a83267495df132..1689e229164f0ec56b03ff95464331220f6ace7a 100644 (file)
@@ -446,16 +446,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;
@@ -464,17 +466,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);
 
@@ -496,6 +500,7 @@ got_bucket:
        atomic_inc(&h->s->pin);
 out_put_head:
        bch2_ec_stripe_head_put(c, h);
+       return 0;
 }
 
 /* Sector allocator */
@@ -573,10 +578,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;
                }
index 72ee53dc95d0fcafdf2750428619858960345258..f1659474b61542af2ddaf5c8c58de5968da7f4e1 100644 (file)
@@ -1228,10 +1228,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;
@@ -1239,7 +1238,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;
 
@@ -1270,7 +1269,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;
        }
@@ -1286,7 +1285,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;
        }
@@ -1352,7 +1351,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;
@@ -1421,14 +1421,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;
                }
 
index 1d4aad50db4d5e7b3fc07e8b8f35e8510221aa67..3f1999bae6d4554c482cf29a6d49472de88bef59 100644 (file)
@@ -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);