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.overstr...@linux.dev>
---
 fs/bcachefs/btree_io.c              | 28 ++++++----------------------
 fs/bcachefs/btree_update_interior.c | 11 +++++------
 fs/bcachefs/btree_update_interior.h |  3 +++
 3 files changed, 14 insertions(+), 28 deletions(-)

diff --git a/fs/bcachefs/btree_io.c b/fs/bcachefs/btree_io.c
index dca5530a2f49..08b22bddd747 100644
--- a/fs/bcachefs/btree_io.c
+++ b/fs/bcachefs/btree_io.c
@@ -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);
diff --git a/fs/bcachefs/btree_update_interior.c 
b/fs/bcachefs/btree_update_interior.c
index e77584607f0d..7bf1bd6a6e92 100644
--- a/fs/bcachefs/btree_update_interior.c
+++ b/fs/bcachefs/btree_update_interior.c
@@ -2293,9 +2293,9 @@ int bch2_btree_node_rewrite(struct btree_trans *trans,
        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);
diff --git a/fs/bcachefs/btree_update_interior.h 
b/fs/bcachefs/btree_update_interior.h
index b649c36c3fbb..ac04e45a8515 100644
--- a/fs/bcachefs/btree_update_interior.h
+++ b/fs/bcachefs/btree_update_interior.h
@@ -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);
-- 
2.50.0


Reply via email to