bcachefs: bch2_check_rebalance_work()
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 14 Mar 2025 13:46:25 +0000 (09:46 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:14:24 +0000 (20:14 -0400)
Add a pass for checking the rebalance_work btree.

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

index d2a7001cf8722e6d8de270b2a910b208fd50f6c0..26c87ab019e87712f70bb5ce643ff82d8231fde0 100644 (file)
@@ -712,3 +712,119 @@ void bch2_fs_rebalance_init(struct bch_fs *c)
 {
        bch2_pd_controller_init(&c->rebalance.pd);
 }
+
+static int check_rebalance_work_one(struct btree_trans *trans,
+                                   struct btree_iter *extent_iter,
+                                   struct btree_iter *rebalance_iter,
+                                   struct bkey_buf *last_flushed)
+{
+       struct bch_fs *c = trans->c;
+       struct bkey_s_c extent_k, rebalance_k;
+       struct printbuf buf = PRINTBUF;
+
+       int ret = bkey_err(extent_k     = bch2_btree_iter_peek(trans, extent_iter)) ?:
+                 bkey_err(rebalance_k  = bch2_btree_iter_peek(trans, rebalance_iter));
+       if (ret)
+               return ret;
+
+       if (!extent_k.k &&
+           extent_iter->btree_id == BTREE_ID_reflink &&
+           (!rebalance_k.k ||
+            rebalance_k.k->p.inode >= BCACHEFS_ROOT_INO)) {
+               bch2_trans_iter_exit(trans, extent_iter);
+               bch2_trans_iter_init(trans, extent_iter,
+                                    BTREE_ID_extents, POS_MIN,
+                                    BTREE_ITER_prefetch|
+                                    BTREE_ITER_all_snapshots);
+               return -BCH_ERR_transaction_restart_nested;
+       }
+
+       if (!extent_k.k && !rebalance_k.k)
+               return 1;
+
+       int cmp = bpos_cmp(extent_k.k    ? extent_k.k->p    : SPOS_MAX,
+                          rebalance_k.k ? rebalance_k.k->p : SPOS_MAX);
+
+       struct bkey deleted;
+       bkey_init(&deleted);
+
+       if (cmp < 0) {
+               deleted.p = extent_k.k->p;
+               rebalance_k.k = &deleted;
+       } else if (cmp > 0) {
+               deleted.p = rebalance_k.k->p;
+               extent_k.k = &deleted;
+       }
+
+       bool should_have_rebalance =
+               bch2_bkey_sectors_need_rebalance(c, extent_k) != 0;
+       bool have_rebalance = rebalance_k.k->type == KEY_TYPE_set;
+
+       if (should_have_rebalance != have_rebalance) {
+               ret = bch2_btree_write_buffer_maybe_flush(trans, extent_k, last_flushed);
+               if (ret)
+                       return ret;
+
+               bch2_bkey_val_to_text(&buf, c, extent_k);
+       }
+
+       if (fsck_err_on(!should_have_rebalance && have_rebalance,
+                       trans, rebalance_work_incorrectly_set,
+                       "rebalance work incorrectly set\n%s", buf.buf)) {
+               ret = bch2_btree_bit_mod_buffered(trans, BTREE_ID_rebalance_work,
+                                                 extent_k.k->p, false);
+               if (ret)
+                       goto err;
+       }
+
+       if (fsck_err_on(should_have_rebalance && !have_rebalance,
+                       trans, rebalance_work_incorrectly_unset,
+                       "rebalance work incorrectly unset\n%s", buf.buf)) {
+               ret = bch2_btree_bit_mod_buffered(trans, BTREE_ID_rebalance_work,
+                                                 extent_k.k->p, true);
+               if (ret)
+                       goto err;
+       }
+
+       if (cmp <= 0)
+               bch2_btree_iter_advance(trans, extent_iter);
+       if (cmp >= 0)
+               bch2_btree_iter_advance(trans, rebalance_iter);
+err:
+fsck_err:
+       printbuf_exit(&buf);
+       return ret;
+}
+
+int bch2_check_rebalance_work(struct bch_fs *c)
+{
+       struct btree_trans *trans = bch2_trans_get(c);
+       struct btree_iter rebalance_iter, extent_iter;
+       int ret = 0;
+
+       bch2_trans_iter_init(trans, &extent_iter,
+                            BTREE_ID_reflink, POS_MIN,
+                            BTREE_ITER_prefetch);
+       bch2_trans_iter_init(trans, &rebalance_iter,
+                            BTREE_ID_rebalance_work, POS_MIN,
+                            BTREE_ITER_prefetch);
+
+       struct bkey_buf last_flushed;
+       bch2_bkey_buf_init(&last_flushed);
+       bkey_init(&last_flushed.k->k);
+
+       while (!ret) {
+               bch2_trans_begin(trans);
+
+               ret = check_rebalance_work_one(trans, &extent_iter, &rebalance_iter, &last_flushed);
+
+               if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
+                       ret = 0;
+       }
+
+       bch2_bkey_buf_exit(&last_flushed, c);
+       bch2_trans_iter_exit(trans, &extent_iter);
+       bch2_trans_iter_exit(trans, &rebalance_iter);
+       bch2_trans_put(trans);
+       return ret < 0 ? ret : 0;
+}
index e5e8eb4a2dd150cfab9b700be9a010581ca03a95..b7c8c0652ad62a4b7ae29eb43a9b6f67095099b8 100644 (file)
@@ -54,4 +54,6 @@ void bch2_rebalance_stop(struct bch_fs *);
 int bch2_rebalance_start(struct bch_fs *);
 void bch2_fs_rebalance_init(struct bch_fs *);
 
+int bch2_check_rebalance_work(struct bch_fs *);
+
 #endif /* _BCACHEFS_REBALANCE_H */
index f9d565bb50dd94cede472985ad1ae1facb21b972..be3185fc6ef4a26389d7f7406f5c01f028d7bb92 100644 (file)
@@ -59,6 +59,7 @@
        x(check_subvolume_structure,            36, PASS_ONLINE|PASS_FSCK)              \
        x(check_directory_structure,            30, PASS_ONLINE|PASS_FSCK)              \
        x(check_nlinks,                         31, PASS_FSCK)                          \
+       x(check_rebalance_work,                 43, PASS_ONLINE|PASS_FSCK)              \
        x(resume_logged_ops,                    23, PASS_ALWAYS)                        \
        x(delete_dead_inodes,                   32, PASS_ALWAYS)                        \
        x(fix_reflink_p,                        33, 0)                                  \