bcachefs: Convert for_each_btree_node() to lockrestart_do()
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 7 Aug 2024 20:34:28 +0000 (16:34 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Wed, 14 Aug 2024 02:56:50 +0000 (22:56 -0400)
for_each_btree_node() now works similarly to for_each_btree_key(), where
the loop body is passed as an argument to be passed to lockrestart_do().

This now calls trans_begin() on every loop iteration - which fixes an
SRCU warning in backpointers fsck.

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

index 3cc02479a9828e81ad787132b364c74484700000..9edc4c5f735c575fc6c74ea95286ce8bdafd2701 100644 (file)
@@ -763,27 +763,22 @@ static int bch2_get_btree_in_memory_pos(struct btree_trans *trans,
             btree < BTREE_ID_NR && !ret;
             btree++) {
                unsigned depth = (BIT_ULL(btree) & btree_leaf_mask) ? 0 : 1;
-               struct btree_iter iter;
-               struct btree *b;
 
                if (!(BIT_ULL(btree) & btree_leaf_mask) &&
                    !(BIT_ULL(btree) & btree_interior_mask))
                        continue;
 
-               bch2_trans_begin(trans);
-
-               __for_each_btree_node(trans, iter, btree,
+               ret = __for_each_btree_node(trans, iter, btree,
                                      btree == start.btree ? start.pos : POS_MIN,
-                                     0, depth, BTREE_ITER_prefetch, b, ret) {
+                                     0, depth, BTREE_ITER_prefetch, b, ({
                        mem_may_pin -= btree_buf_bytes(b);
                        if (mem_may_pin <= 0) {
                                c->btree_cache.pinned_nodes_end = *end =
                                        BBPOS(btree, b->key.k.p);
-                               bch2_trans_iter_exit(trans, &iter);
-                               return 0;
+                               break;
                        }
-               }
-               bch2_trans_iter_exit(trans, &iter);
+                       0;
+               }));
        }
 
        return ret;
index aa8a049071f410d05fcfdd6d85d3ef1f0329948c..2e84d22e17bdd616b681625d4b022e6d4e2a3dda 100644 (file)
@@ -1900,6 +1900,7 @@ err:
        goto out;
 }
 
+/* Only kept for -tools */
 struct btree *bch2_btree_iter_peek_node_and_restart(struct btree_iter *iter)
 {
        struct btree *b;
index c7725865309c093647a1a7ade9dd0dfc6a458e0d..dca62375d7d30fd1eef504655c56520dc6d03cec 100644 (file)
@@ -600,23 +600,35 @@ void bch2_trans_srcu_unlock(struct btree_trans *);
 
 u32 bch2_trans_begin(struct btree_trans *);
 
-/*
- * XXX
- * this does not handle transaction restarts from bch2_btree_iter_next_node()
- * correctly
- */
-#define __for_each_btree_node(_trans, _iter, _btree_id, _start,                \
-                             _locks_want, _depth, _flags, _b, _ret)    \
-       for (bch2_trans_node_iter_init((_trans), &(_iter), (_btree_id), \
-                               _start, _locks_want, _depth, _flags);   \
-            (_b) = bch2_btree_iter_peek_node_and_restart(&(_iter)),    \
-            !((_ret) = PTR_ERR_OR_ZERO(_b)) && (_b);                   \
-            (_b) = bch2_btree_iter_next_node(&(_iter)))
+#define __for_each_btree_node(_trans, _iter, _btree_id, _start,                        \
+                             _locks_want, _depth, _flags, _b, _do)             \
+({                                                                             \
+       bch2_trans_begin((_trans));                                             \
+                                                                               \
+       struct btree_iter _iter;                                                \
+       bch2_trans_node_iter_init((_trans), &_iter, (_btree_id),                \
+                                 _start, _locks_want, _depth, _flags);         \
+       int _ret3 = 0;                                                          \
+       do {                                                                    \
+               _ret3 = lockrestart_do((_trans), ({                             \
+                       struct btree *_b = bch2_btree_iter_peek_node(&_iter);   \
+                       if (!_b)                                                \
+                               break;                                          \
+                                                                               \
+                       PTR_ERR_OR_ZERO(_b) ?: (_do);                           \
+               })) ?:                                                          \
+               lockrestart_do((_trans),                                        \
+                       PTR_ERR_OR_ZERO(bch2_btree_iter_next_node(&_iter)));    \
+       } while (!_ret3);                                                       \
+                                                                               \
+       bch2_trans_iter_exit((_trans), &(_iter));                               \
+       _ret3;                                                                  \
+})
 
 #define for_each_btree_node(_trans, _iter, _btree_id, _start,          \
-                           _flags, _b, _ret)                           \
-       __for_each_btree_node(_trans, _iter, _btree_id, _start,         \
-                             0, 0, _flags, _b, _ret)
+                           _flags, _b, _do)                            \
+       __for_each_btree_node(_trans, _iter, _btree_id, _start, \
+                             0, 0, _flags, _b, _do)
 
 static inline struct bkey_s_c bch2_btree_iter_peek_prev_type(struct btree_iter *iter,
                                                             unsigned flags)
index ebabab171fe5eac2fe665094f1070e65de5e891c..45aec1afdb0e31195ffc76a19cc9d048669be299 100644 (file)
@@ -397,47 +397,27 @@ static ssize_t bch2_read_btree_formats(struct file *file, char __user *buf,
                                       size_t size, loff_t *ppos)
 {
        struct dump_iter *i = file->private_data;
-       struct btree_trans *trans;
-       struct btree_iter iter;
-       struct btree *b;
-       ssize_t ret;
 
        i->ubuf = buf;
        i->size = size;
        i->ret  = 0;
 
-       ret = flush_buf(i);
+       ssize_t ret = flush_buf(i);
        if (ret)
                return ret;
 
        if (bpos_eq(SPOS_MAX, i->from))
                return i->ret;
 
-       trans = bch2_trans_get(i->c);
-retry:
-       bch2_trans_begin(trans);
-
-       for_each_btree_node(trans, iter, i->id, i->from, 0, b, ret) {
-               bch2_btree_node_to_text(&i->buf, i->c, b);
-               i->from = !bpos_eq(SPOS_MAX, b->key.k.p)
-                       ? bpos_successor(b->key.k.p)
-                       : b->key.k.p;
-
-               ret = drop_locks_do(trans, flush_buf(i));
-               if (ret)
-                       break;
-       }
-       bch2_trans_iter_exit(trans, &iter);
-
-       if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
-               goto retry;
-
-       bch2_trans_put(trans);
-
-       if (!ret)
-               ret = flush_buf(i);
+       return bch2_trans_run(i->c,
+               for_each_btree_node(trans, iter, i->id, i->from, 0, b, ({
+                       bch2_btree_node_to_text(&i->buf, i->c, b);
+                       i->from = !bpos_eq(SPOS_MAX, b->key.k.p)
+                               ? bpos_successor(b->key.k.p)
+                               : b->key.k.p;
 
-       return ret ?: i->ret;
+                       drop_locks_do(trans, flush_buf(i));
+               }))) ?: i->ret;
 }
 
 static const struct file_operations btree_format_debug_ops = {