bcachefs: Second layer of refcounting for new stripes
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 9 Mar 2023 15:18:09 +0000 (10:18 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:56 +0000 (17:09 -0400)
This will be used for move writes, which will be waiting until the
stripe is created to do the index update. They need to prevent the
stripe from being reclaimed until their index update is done, so we need
another refcount that just keeps the stripe open.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
# Conflicts:
# fs/bcachefs/ec.c
# fs/bcachefs/io.c

fs/bcachefs/alloc_foreground.c
fs/bcachefs/ec.c
fs/bcachefs/ec.h

index 4621ef7f1e507478d401a87092f54f371d7f310c..7c81189bcd621e77d385abc960a3cb20a9c05405 100644 (file)
@@ -97,7 +97,7 @@ void __bch2_open_bucket_put(struct bch_fs *c, struct open_bucket *ob)
        struct bch_dev *ca = bch_dev_bkey_exists(c, ob->dev);
 
        if (ob->ec) {
-               ec_stripe_new_put(c, ob->ec);
+               ec_stripe_new_put(c, ob->ec, STRIPE_REF_io);
                return;
        }
 
@@ -799,7 +799,7 @@ got_bucket:
 
        ob->ec_idx      = ec_idx;
        ob->ec          = h->s;
-       ec_stripe_new_get(h->s);
+       ec_stripe_new_get(h->s, STRIPE_REF_io);
 
        ret = add_new_bucket(c, ptrs, devs_may_alloc,
                             nr_replicas, nr_effective,
index 1fd68d44b90f29e924fe224ea1eeecd6127e5a16..0a2e7db6906fb6842cb19c90368490fab3f4e4c3 100644 (file)
@@ -1057,6 +1057,13 @@ static void zero_out_rest_of_ec_bucket(struct bch_fs *c,
                s->err = ret;
 }
 
+void bch2_ec_stripe_new_free(struct bch_fs *c, struct ec_stripe_new *s)
+{
+       if (s->idx)
+               bch2_stripe_close(c, s);
+       kfree(s);
+}
+
 /*
  * data buckets of new stripe all written: create the stripe
  */
@@ -1152,13 +1159,11 @@ err:
        list_del(&s->list);
        mutex_unlock(&c->ec_stripe_new_lock);
 
-       if (s->idx)
-               bch2_stripe_close(c, s);
-
        ec_stripe_buf_exit(&s->existing_stripe);
        ec_stripe_buf_exit(&s->new_stripe);
        closure_debug_destroy(&s->iodone);
-       kfree(s);
+
+       ec_stripe_new_put(c, s, STRIPE_REF_stripe);
 }
 
 static struct ec_stripe_new *get_pending_stripe(struct bch_fs *c)
@@ -1167,7 +1172,7 @@ static struct ec_stripe_new *get_pending_stripe(struct bch_fs *c)
 
        mutex_lock(&c->ec_stripe_new_lock);
        list_for_each_entry(s, &c->ec_stripe_new_list, list)
-               if (!atomic_read(&s->pin))
+               if (!atomic_read(&s->ref[STRIPE_REF_io]))
                        goto out;
        s = NULL;
 out:
@@ -1209,7 +1214,7 @@ static void ec_stripe_set_pending(struct bch_fs *c, struct ec_stripe_head *h)
        list_add(&s->list, &c->ec_stripe_new_list);
        mutex_unlock(&c->ec_stripe_new_lock);
 
-       ec_stripe_new_put(c, s);
+       ec_stripe_new_put(c, s, STRIPE_REF_io);
 }
 
 void bch2_ec_bucket_cancel(struct bch_fs *c, struct open_bucket *ob)
@@ -1321,7 +1326,8 @@ static int ec_new_stripe_alloc(struct bch_fs *c, struct ec_stripe_head *h)
 
        mutex_init(&s->lock);
        closure_init(&s->iodone, NULL);
-       atomic_set(&s->pin, 1);
+       atomic_set(&s->ref[STRIPE_REF_stripe], 1);
+       atomic_set(&s->ref[STRIPE_REF_io], 1);
        s->c            = c;
        s->h            = h;
        s->nr_data      = min_t(unsigned, h->nr_active_devs,
@@ -1829,13 +1835,16 @@ void bch2_stripes_heap_to_text(struct printbuf *out, struct bch_fs *c)
        size_t i;
 
        mutex_lock(&c->ec_stripes_heap_lock);
-       for (i = 0; i < min_t(size_t, h->used, 20); i++) {
+       for (i = 0; i < min_t(size_t, h->used, 50); i++) {
                m = genradix_ptr(&c->stripes, h->data[i].idx);
 
-               prt_printf(out, "%zu %u/%u+%u\n", h->data[i].idx,
+               prt_printf(out, "%zu %u/%u+%u", h->data[i].idx,
                       h->data[i].blocks_nonempty,
                       m->nr_blocks - m->nr_redundant,
                       m->nr_redundant);
+               if (bch2_stripe_is_open(c, h->data[i].idx))
+                       prt_str(out, " open");
+               prt_newline(out);
        }
        mutex_unlock(&c->ec_stripes_heap_lock);
 }
@@ -1860,9 +1869,10 @@ void bch2_new_stripes_to_text(struct printbuf *out, struct bch_fs *c)
 
        mutex_lock(&c->ec_stripe_new_lock);
        list_for_each_entry(s, &c->ec_stripe_new_list, list) {
-               prt_printf(out, "\tin flight: idx %llu blocks %u+%u pin %u\n",
+               prt_printf(out, "\tin flight: idx %llu blocks %u+%u ref %u %u\n",
                           s->idx, s->nr_data, s->nr_parity,
-                          atomic_read(&s->pin));
+                          atomic_read(&s->ref[STRIPE_REF_io]),
+                          atomic_read(&s->ref[STRIPE_REF_stripe]));
        }
        mutex_unlock(&c->ec_stripe_new_lock);
 }
index d112aea9ec5632f0339532fd39c3e2407fceedc2..8f777a37e43d77591506271a8a205f61261c8cfa 100644 (file)
@@ -143,6 +143,12 @@ struct ec_stripe_buf {
 
 struct ec_stripe_head;
 
+enum ec_stripe_ref {
+       STRIPE_REF_io,
+       STRIPE_REF_stripe,
+       STRIPE_REF_NR
+};
+
 struct ec_stripe_new {
        struct bch_fs           *c;
        struct ec_stripe_head   *h;
@@ -154,8 +160,7 @@ struct ec_stripe_new {
 
        struct closure          iodone;
 
-       /* counts in flight writes, stripe is created when pin == 0 */
-       atomic_t                pin;
+       atomic_t                ref[STRIPE_REF_NR];
 
        int                     err;
 
@@ -213,19 +218,30 @@ void bch2_stripes_heap_insert(struct bch_fs *, struct stripe *, size_t);
 
 void bch2_do_stripe_deletes(struct bch_fs *);
 void bch2_ec_do_stripe_creates(struct bch_fs *);
+void bch2_ec_stripe_new_free(struct bch_fs *, struct ec_stripe_new *);
 
-static inline void ec_stripe_new_get(struct ec_stripe_new *s)
+static inline void ec_stripe_new_get(struct ec_stripe_new *s,
+                                    enum ec_stripe_ref ref)
 {
-       atomic_inc(&s->pin);
+       atomic_inc(&s->ref[ref]);
 }
 
-static inline void ec_stripe_new_put(struct bch_fs *c, struct ec_stripe_new *s)
+static inline void ec_stripe_new_put(struct bch_fs *c, struct ec_stripe_new *s,
+                                    enum ec_stripe_ref ref)
 {
-       BUG_ON(atomic_read(&s->pin) <= 0);
-       BUG_ON(!s->err && !s->idx);
-
-       if (atomic_dec_and_test(&s->pin))
-               bch2_ec_do_stripe_creates(c);
+       BUG_ON(atomic_read(&s->ref[ref]) <= 0);
+
+       if (atomic_dec_and_test(&s->ref[ref]))
+               switch (ref) {
+               case STRIPE_REF_stripe:
+                       bch2_ec_stripe_new_free(c, s);
+                       break;
+               case STRIPE_REF_io:
+                       bch2_ec_do_stripe_creates(c);
+                       break;
+               default:
+                       unreachable();
+               }
 }
 
 void bch2_ec_stop_dev(struct bch_fs *, struct bch_dev *);