bcachefs: Fix a deadlock in the RO path
authorKent Overstreet <kent.overstreet@gmail.com>
Wed, 17 Jun 2020 21:30:38 +0000 (17:30 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:41 +0000 (17:08 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_gc.c
fs/bcachefs/buckets.c

index 3775b65a89a684dbd231732329efe989baf2d2f0..cdd4bc334530f359acd0287af03c7763e5bf3e2f 100644 (file)
@@ -932,7 +932,12 @@ int bch2_gc_gens(struct bch_fs *c)
        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) {
                down_read(&ca->bucket_lock);
@@ -959,7 +964,7 @@ int bch2_gc_gens(struct bch_fs *c)
                up_read(&ca->bucket_lock);
        }
 err:
-       up_read(&c->state_lock);
+       up_read(&c->gc_lock);
        return ret;
 }
 
index 2c9ba18357fdeffb57e77d13d0ff064c200158c9..1ae9403847cae33a831505fae14c42d69901a817 100644 (file)
@@ -2003,6 +2003,7 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
        bch2_copygc_stop(ca);
 
        if (resize) {
+               down_write(&c->gc_lock);
                down_write(&ca->bucket_lock);
                percpu_down_write(&c->mark_lock);
        }
@@ -2025,8 +2026,10 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
 
        swap(ca->buckets_nouse, buckets_nouse);
 
-       if (resize)
+       if (resize) {
                percpu_up_write(&c->mark_lock);
+               up_write(&c->gc_lock);
+       }
 
        spin_lock(&c->freelist_lock);
        for (i = 0; i < RESERVE_NR; i++) {