bcachefs: Fix bch2_check_discard_freespace_key()
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 18 Jun 2023 17:25:35 +0000 (13:25 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:10:04 +0000 (17:10 -0400)
We weren't correctly checking the freespace btree - it's an extents
btree, which means we need to iterate over each bucket in a freespace
extent.

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

index f774a660a68122e561082399e0f84d306ddb8eeb..6c8bcb210ad9eafb41b333ace26b064da2ac71f7 100644 (file)
@@ -788,10 +788,12 @@ static int bch2_bucket_do_index(struct btree_trans *trans,
        if (ca->mi.freespace_initialized &&
            test_bit(BCH_FS_CHECK_ALLOC_DONE, &c->flags) &&
            bch2_trans_inconsistent_on(old.k->type != old_type, trans,
-                       "incorrect key when %s %s btree (got %s should be %s)\n"
+                       "incorrect key when %s %s:%llu:%llu:0 (got %s should be %s)\n"
                        "  for %s",
                        set ? "setting" : "clearing",
                        bch2_btree_ids[btree],
+                       iter.pos.inode,
+                       iter.pos.offset,
                        bch2_bkey_types[old.k->type],
                        bch2_bkey_types[old_type],
                        (bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf))) {
@@ -1278,8 +1280,8 @@ fsck_err:
        return ret;
 }
 
-static int bch2_check_discard_freespace_key(struct btree_trans *trans,
-                                           struct btree_iter *iter)
+static int __bch2_check_discard_freespace_key(struct btree_trans *trans,
+                                             struct btree_iter *iter)
 {
        struct bch_fs *c = trans->c;
        struct btree_iter alloc_iter;
@@ -1313,23 +1315,46 @@ static int bch2_check_discard_freespace_key(struct btree_trans *trans,
        if (fsck_err_on(a->data_type != state ||
                        (state == BCH_DATA_free &&
                         genbits != alloc_freespace_genbits(*a)), c,
-                       "%s\n  incorrectly set in %s index (free %u, genbits %llu should be %llu)",
+                       "%s\n  incorrectly set at %s:%llu:%llu:0 (free %u, genbits %llu should be %llu)",
                        (bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf),
                        bch2_btree_ids[iter->btree_id],
+                       iter->pos.inode,
+                       iter->pos.offset,
                        a->data_type == state,
                        genbits >> 56, alloc_freespace_genbits(*a) >> 56))
                goto delete;
 out:
 fsck_err:
+       set_btree_iter_dontneed(&alloc_iter);
        bch2_trans_iter_exit(trans, &alloc_iter);
        printbuf_exit(&buf);
        return ret;
 delete:
-       ret = bch2_btree_delete_extent_at(trans, iter,
-                       iter->btree_id == BTREE_ID_freespace ? 1 : 0, 0);
+       ret =   bch2_btree_delete_extent_at(trans, iter,
+                       iter->btree_id == BTREE_ID_freespace ? 1 : 0, 0) ?:
+               bch2_trans_commit(trans, NULL, NULL,
+                       BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW);
        goto out;
 }
 
+static int bch2_check_discard_freespace_key(struct btree_trans *trans,
+                                           struct btree_iter *iter,
+                                           struct bpos end)
+{
+       if (!btree_node_type_is_extents(iter->btree_id)) {
+               return __bch2_check_discard_freespace_key(trans, iter);
+       } else {
+               int ret = 0;
+
+               while (!bkey_eq(iter->pos, end) &&
+                      !(ret = btree_trans_too_many_iters(trans) ?:
+                              __bch2_check_discard_freespace_key(trans, iter)))
+                       bch2_btree_iter_set_pos(iter, bpos_nosnap_successor(iter->pos));
+
+               return ret;
+       }
+}
+
 /*
  * We've already checked that generation numbers in the bucket_gens btree are
  * valid for buckets that exist; this just checks for keys for nonexistent
@@ -1481,16 +1506,14 @@ bkey_err:
        if (ret < 0)
                goto err;
 
-       ret = for_each_btree_key_commit(&trans, iter,
+       ret = for_each_btree_key2(&trans, iter,
                        BTREE_ID_need_discard, POS_MIN,
                        BTREE_ITER_PREFETCH, k,
-                       NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
-               bch2_check_discard_freespace_key(&trans, &iter)) ?:
-             for_each_btree_key_commit(&trans, iter,
+               bch2_check_discard_freespace_key(&trans, &iter, k.k->p)) ?:
+             for_each_btree_key2(&trans, iter,
                        BTREE_ID_freespace, POS_MIN,
                        BTREE_ITER_PREFETCH, k,
-                       NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
-               bch2_check_discard_freespace_key(&trans, &iter)) ?:
+               bch2_check_discard_freespace_key(&trans, &iter, k.k->p)) ?:
              for_each_btree_key_commit(&trans, iter,
                        BTREE_ID_bucket_gens, POS_MIN,
                        BTREE_ITER_PREFETCH, k,