aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorGravatar Kent Overstreet <kent.overstreet@linux.dev> 2023-02-18 21:10:13 -0500
committerGravatar Kent Overstreet <kent.overstreet@linux.dev> 2023-10-22 17:09:53 -0400
commitebe8bd75a073c303e695589c11f298fcc3a1fb1c (patch)
treedcb830c0beb571413d5ab8a094a7b14e65f2f6cc /fs
parentbcachefs: Switch ec_stripes_heap_lock to a mutex (diff)
downloadlinux-ebe8bd75a073c303e695589c11f298fcc3a1fb1c.tar.gz
linux-ebe8bd75a073c303e695589c11f298fcc3a1fb1c.tar.bz2
linux-ebe8bd75a073c303e695589c11f298fcc3a1fb1c.zip
bcachefs: Improve c->writes refcounting for stripe create path
This makes our handling of c->writes more consistent with other asynchronous work items. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs')
-rw-r--r--fs/bcachefs/ec.c54
1 files changed, 33 insertions, 21 deletions
diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c
index 7a6b962ae1fc..44e7b6584713 100644
--- a/fs/bcachefs/ec.c
+++ b/fs/bcachefs/ec.c
@@ -982,9 +982,6 @@ static void ec_stripe_create(struct ec_stripe_new *s)
BUG_ON(!s->allocated);
- if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_stripe_create))
- goto err;
-
ec_generate_ec(&s->new_stripe);
ec_generate_checksums(&s->new_stripe);
@@ -996,7 +993,7 @@ static void ec_stripe_create(struct ec_stripe_new *s)
if (ec_nr_failed(&s->new_stripe)) {
bch_err(c, "error creating stripe: error writing redundancy buckets");
- goto err_put_writes;
+ goto err;
}
ret = bch2_trans_do(c, &s->res, NULL, BTREE_INSERT_NOFAIL,
@@ -1005,7 +1002,7 @@ static void ec_stripe_create(struct ec_stripe_new *s)
: ec_stripe_bkey_insert(&trans, &s->new_stripe.key, &s->res));
if (ret) {
bch_err(c, "error creating stripe: error creating stripe key");
- goto err_put_writes;
+ goto err;
}
ret = ec_stripe_update_extents(c, &s->new_stripe);
@@ -1013,15 +1010,12 @@ static void ec_stripe_create(struct ec_stripe_new *s)
bch_err(c, "error creating stripe: error updating pointers: %s",
bch2_err_str(ret));
-
mutex_lock(&c->ec_stripes_heap_lock);
m = genradix_ptr(&c->stripes, s->new_stripe.key.k.p.offset);
BUG_ON(m->on_heap);
bch2_stripes_heap_insert(c, m, s->new_stripe.key.k.p.offset);
mutex_unlock(&c->ec_stripes_heap_lock);
-err_put_writes:
- bch2_write_ref_put(c, BCH_WRITE_REF_stripe_create);
err:
bch2_disk_reservation_put(c, &s->res);
@@ -1043,31 +1037,49 @@ err:
kfree(s);
}
-static void ec_stripe_create_work(struct work_struct *work)
+static struct ec_stripe_new *get_pending_stripe(struct bch_fs *c)
{
- struct bch_fs *c = container_of(work,
- struct bch_fs, ec_stripe_create_work);
- struct ec_stripe_new *s, *n;
-restart:
+ struct ec_stripe_new *s;
+
mutex_lock(&c->ec_stripe_new_lock);
- list_for_each_entry_safe(s, n, &c->ec_stripe_new_list, list)
+ list_for_each_entry(s, &c->ec_stripe_new_list, list)
if (!atomic_read(&s->pin)) {
list_del(&s->list);
- mutex_unlock(&c->ec_stripe_new_lock);
- ec_stripe_create(s);
- goto restart;
+ goto out;
}
+ s = NULL;
+out:
mutex_unlock(&c->ec_stripe_new_lock);
+
+ return s;
+}
+
+static void ec_stripe_create_work(struct work_struct *work)
+{
+ struct bch_fs *c = container_of(work,
+ struct bch_fs, ec_stripe_create_work);
+ struct ec_stripe_new *s;
+
+ while ((s = get_pending_stripe(c)))
+ ec_stripe_create(s);
+
+ bch2_write_ref_put(c, BCH_WRITE_REF_stripe_create);
+}
+
+void bch2_ec_do_stripe_creates(struct bch_fs *c)
+{
+ bch2_write_ref_get(c, BCH_WRITE_REF_stripe_create);
+
+ if (!queue_work(system_long_wq, &c->ec_stripe_create_work))
+ bch2_write_ref_put(c, BCH_WRITE_REF_stripe_create);
}
static void ec_stripe_new_put(struct bch_fs *c, struct ec_stripe_new *s)
{
BUG_ON(atomic_read(&s->pin) <= 0);
- if (atomic_dec_and_test(&s->pin)) {
- BUG_ON(!s->pending);
- queue_work(system_long_wq, &c->ec_stripe_create_work);
- }
+ if (atomic_dec_and_test(&s->pin))
+ bch2_ec_do_stripe_creates(c);
}
static void ec_stripe_set_pending(struct bch_fs *c, struct ec_stripe_head *h)