bcachefs: Fix btree_gc when multiple passes required
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 13 Dec 2022 19:43:03 +0000 (14:43 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:48 +0000 (17:09 -0400)
We weren't resetting filesystem & device usage when restarting gc, which
was spotted when free bucket counters overflowed - whoops.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_gc.c

index 2defa811f48fb84c92e33d3557a9a84fee72647f..d4a0e0a716c57d0a560ce31c4a797b9eb0a54817 100644 (file)
@@ -1282,8 +1282,7 @@ fsck_err:
        return ret;
 }
 
-static int bch2_gc_start(struct bch_fs *c,
-                        bool metadata_only)
+static int bch2_gc_start(struct bch_fs *c)
 {
        struct bch_dev *ca = NULL;
        unsigned i;
@@ -1298,7 +1297,6 @@ static int bch2_gc_start(struct bch_fs *c,
        }
 
        for_each_member_device(ca, c, i) {
-               BUG_ON(ca->buckets_gc);
                BUG_ON(ca->usage_gc);
 
                ca->usage_gc = alloc_percpu(struct bch_dev_usage);
@@ -1315,6 +1313,22 @@ static int bch2_gc_start(struct bch_fs *c,
        return 0;
 }
 
+static int bch2_gc_reset(struct bch_fs *c)
+{
+       struct bch_dev *ca;
+       unsigned i;
+
+       for_each_member_device(ca, c, i) {
+               free_percpu(ca->usage_gc);
+               ca->usage_gc = NULL;
+       }
+
+       free_percpu(c->usage_gc);
+       c->usage_gc = NULL;
+
+       return bch2_gc_start(c);
+}
+
 /* returns true if not equal */
 static inline bool bch2_alloc_v4_cmp(struct bch_alloc_v4 l,
                                     struct bch_alloc_v4 r)
@@ -1761,7 +1775,7 @@ int bch2_gc(struct bch_fs *c, bool initial, bool metadata_only)
 
        bch2_btree_interior_updates_flush(c);
 
-       ret   = bch2_gc_start(c, metadata_only) ?:
+       ret   = bch2_gc_start(c) ?:
                bch2_gc_alloc_start(c, metadata_only) ?:
                bch2_gc_reflink_start(c, metadata_only);
        if (ret)
@@ -1822,6 +1836,9 @@ again:
                bch2_gc_stripes_reset(c, metadata_only);
                bch2_gc_alloc_reset(c, metadata_only);
                bch2_gc_reflink_reset(c, metadata_only);
+               ret = bch2_gc_reset(c);
+               if (ret)
+                       goto out;
 
                /* flush fsck errors, reset counters */
                bch2_flush_fsck_errs(c);