summaryrefslogtreecommitdiff
path: root/libbcachefs/btree_gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/btree_gc.c')
-rw-r--r--libbcachefs/btree_gc.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/libbcachefs/btree_gc.c b/libbcachefs/btree_gc.c
index e8abc193..8771ef1f 100644
--- a/libbcachefs/btree_gc.c
+++ b/libbcachefs/btree_gc.c
@@ -902,6 +902,7 @@ static int bch2_gc_btree_gens(struct bch_fs *c, enum btree_id id)
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
const struct bch_extent_ptr *ptr;
+ percpu_down_read(&c->mark_lock);
bkey_for_each_ptr(ptrs, ptr) {
struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
struct bucket *g = PTR_BUCKET(ca, ptr, false);
@@ -914,6 +915,7 @@ static int bch2_gc_btree_gens(struct bch_fs *c, enum btree_id id)
}
}
+ percpu_up_read(&c->mark_lock);
}
bch2_trans_exit(&trans);
@@ -923,17 +925,25 @@ static int bch2_gc_btree_gens(struct bch_fs *c, enum btree_id id)
int bch2_gc_gens(struct bch_fs *c)
{
struct bch_dev *ca;
+ struct bucket_array *buckets;
+ struct bucket *g;
unsigned i;
int ret;
- down_read(&c->state_lock);
+ /*
+ * Ideally we would be using state_lock and not gc_lock here, but that
+ * introduces a deadlock in the RO path - we currently take the state
+ * lock at the start of going RO, thus the gc thread may get stuck:
+ */
+ down_read(&c->gc_lock);
for_each_member_device(ca, c, i) {
- struct bucket_array *buckets = bucket_array(ca);
- struct bucket *g;
+ down_read(&ca->bucket_lock);
+ buckets = bucket_array(ca);
for_each_bucket(g, buckets)
g->gc_gen = g->mark.gen;
+ up_read(&ca->bucket_lock);
}
for (i = 0; i < BTREE_ID_NR; i++)
@@ -944,14 +954,15 @@ int bch2_gc_gens(struct bch_fs *c)
}
for_each_member_device(ca, c, i) {
- struct bucket_array *buckets = bucket_array(ca);
- struct bucket *g;
+ down_read(&ca->bucket_lock);
+ buckets = bucket_array(ca);
for_each_bucket(g, buckets)
g->oldest_gen = g->gc_gen;
+ up_read(&ca->bucket_lock);
}
err:
- up_read(&c->state_lock);
+ up_read(&c->gc_lock);
return ret;
}