bcachefs: Fix restart handling in btree_node_scrub_work()
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 17 Jun 2025 14:23:53 +0000 (10:23 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Tue, 17 Jun 2025 15:42:06 +0000 (11:42 -0400)
btree node scrub was sometimes failing to rewrite nodes with errors;
bch2_btree_node_rewrite() can return a transaction restart and we
weren't checking - the lockrestart_do() needs to wrap the entire
operation.

And there's a better helper it should've been using,
bch2_btree_node_rewrite_key(), which makes all this more convenient.

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

index dca5530a2f493176c464000b548fcd3a0a7c435f..08b22bddd7470f18a5c9567c76264cff826ffd6f 100644 (file)
@@ -1986,28 +1986,12 @@ static void btree_node_scrub_work(struct work_struct *work)
        prt_newline(&err);
 
        if (!btree_node_scrub_check(c, scrub->buf, scrub->written, &err)) {
-               struct btree_trans *trans = bch2_trans_get(c);
-
-               struct btree_iter iter;
-               bch2_trans_node_iter_init(trans, &iter, scrub->btree,
-                                         scrub->key.k->k.p, 0, scrub->level - 1, 0);
-
-               struct btree *b;
-               int ret = lockrestart_do(trans,
-                       PTR_ERR_OR_ZERO(b = bch2_btree_iter_peek_node(trans, &iter)));
-               if (ret)
-                       goto err;
-
-               if (bkey_i_to_btree_ptr_v2(&b->key)->v.seq == scrub->seq) {
-                       bch_err(c, "error validating btree node during scrub on %s at btree %s",
-                               scrub->ca->name, err.buf);
-
-                       ret = bch2_btree_node_rewrite(trans, &iter, b, 0, 0);
-               }
-err:
-               bch2_trans_iter_exit(trans, &iter);
-               bch2_trans_begin(trans);
-               bch2_trans_put(trans);
+               int ret = bch2_trans_do(c,
+                       bch2_btree_node_rewrite_key(trans, scrub->btree, scrub->level - 1,
+                                                   scrub->key.k, 0));
+               if (!bch2_err_matches(ret, ENOENT) &&
+                   !bch2_err_matches(ret, EROFS))
+                       bch_err_fn_ratelimited(c, ret);
        }
 
        printbuf_exit(&err);
index e77584607f0d377b28db9053a26917c6353732be..7bf1bd6a6e928677370c5a8d4930b3f2151715e7 100644 (file)
@@ -2293,9 +2293,9 @@ err:
        goto out;
 }
 
-static int bch2_btree_node_rewrite_key(struct btree_trans *trans,
-                                      enum btree_id btree, unsigned level,
-                                      struct bkey_i *k, unsigned flags)
+int bch2_btree_node_rewrite_key(struct btree_trans *trans,
+                               enum btree_id btree, unsigned level,
+                               struct bkey_i *k, unsigned flags)
 {
        struct btree_iter iter;
        bch2_trans_node_iter_init(trans, &iter,
@@ -2367,9 +2367,8 @@ static void async_btree_node_rewrite_work(struct work_struct *work)
 
        int ret = bch2_trans_do(c, bch2_btree_node_rewrite_key(trans,
                                                a->btree_id, a->level, a->key.k, 0));
-       if (ret != -ENOENT &&
-           !bch2_err_matches(ret, EROFS) &&
-           ret != -BCH_ERR_journal_shutdown)
+       if (!bch2_err_matches(ret, ENOENT) &&
+           !bch2_err_matches(ret, EROFS))
                bch_err_fn_ratelimited(c, ret);
 
        spin_lock(&c->btree_node_rewrites_lock);
index b649c36c3fbb70c613e92d389ef7b1717461fbaa..ac04e45a85159467c4ead4ff82d5a68d6bc6d8b4 100644 (file)
@@ -176,6 +176,9 @@ static inline int bch2_foreground_maybe_merge(struct btree_trans *trans,
 
 int bch2_btree_node_rewrite(struct btree_trans *, struct btree_iter *,
                            struct btree *, unsigned, unsigned);
+int bch2_btree_node_rewrite_key(struct btree_trans *,
+                               enum btree_id, unsigned,
+                               struct bkey_i *, unsigned);
 int bch2_btree_node_rewrite_pos(struct btree_trans *,
                                enum btree_id, unsigned,
                                struct bpos, unsigned, unsigned);