bcachefs: Add more flags to btree nodes for rewrite reason
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 6 Jun 2025 00:53:01 +0000 (20:53 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 12 Jun 2025 03:21:30 +0000 (23:21 -0400)
It seems excessive forced btree node rewrites can cause interior btree
updates to become wedged during recovery, before we're using the write
buffer for backpointer updates.

Add more flags so we can determine where these are coming from.

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

index 57eff3012a7b7c7e6ccbaa311d5f70c666724ee5..6787d5b91eabb3d7b003ed1cdb7de6f05c04382d 100644 (file)
@@ -1045,6 +1045,7 @@ got_good_key:
                le16_add_cpu(&i->u64s, -next_good_key);
                memmove_u64s_down(k, (u64 *) k + next_good_key, (u64 *) vstruct_end(i) - (u64 *) k);
                set_btree_node_need_rewrite(b);
+               set_btree_node_need_rewrite_error(b);
        }
 fsck_err:
        printbuf_exit(&buf);
@@ -1305,6 +1306,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
                                          (u64 *) vstruct_end(i) - (u64 *) k);
                        set_btree_bset_end(b, b->set);
                        set_btree_node_need_rewrite(b);
+                       set_btree_node_need_rewrite_error(b);
                        continue;
                }
                if (ret)
@@ -1329,12 +1331,16 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
                bkey_for_each_ptr(bch2_bkey_ptrs(bkey_i_to_s(&b->key)), ptr) {
                        struct bch_dev *ca2 = bch2_dev_rcu(c, ptr->dev);
 
-                       if (!ca2 || ca2->mi.state != BCH_MEMBER_STATE_rw)
+                       if (!ca2 || ca2->mi.state != BCH_MEMBER_STATE_rw) {
                                set_btree_node_need_rewrite(b);
+                               set_btree_node_need_rewrite_degraded(b);
+                       }
                }
 
-       if (!ptr_written)
+       if (!ptr_written) {
                set_btree_node_need_rewrite(b);
+               set_btree_node_need_rewrite_ptr_written_zero(b);
+       }
 fsck_err:
        mempool_free(iter, &c->fill_iter);
        printbuf_exit(&buf);
index c61c4171ae506a11e217fea2770d04cdfdeca8be..3aa4a602bd02689d5c2f8eb78e3137b6b1a2a798 100644 (file)
@@ -617,6 +617,9 @@ enum btree_write_type {
        x(dying)                                                        \
        x(fake)                                                         \
        x(need_rewrite)                                                 \
+       x(need_rewrite_error)                                           \
+       x(need_rewrite_degraded)                                        \
+       x(need_rewrite_ptr_written_zero)                                \
        x(never_write)                                                  \
        x(pinned)
 
@@ -641,6 +644,32 @@ static inline void clear_btree_node_ ## flag(struct btree *b)              \
 BTREE_FLAGS()
 #undef x
 
+#define BTREE_NODE_REWRITE_REASON()                                    \
+       x(none)                                                         \
+       x(unknown)                                                      \
+       x(error)                                                        \
+       x(degraded)                                                     \
+       x(ptr_written_zero)
+
+enum btree_node_rewrite_reason {
+#define x(n)   BTREE_NODE_REWRITE_##n,
+       BTREE_NODE_REWRITE_REASON()
+#undef x
+};
+
+static inline enum btree_node_rewrite_reason btree_node_rewrite_reason(struct btree *b)
+{
+       if (btree_node_need_rewrite_ptr_written_zero(b))
+               return BTREE_NODE_REWRITE_ptr_written_zero;
+       if (btree_node_need_rewrite_degraded(b))
+               return BTREE_NODE_REWRITE_degraded;
+       if (btree_node_need_rewrite_error(b))
+               return BTREE_NODE_REWRITE_error;
+       if (btree_node_need_rewrite(b))
+               return BTREE_NODE_REWRITE_unknown;
+       return BTREE_NODE_REWRITE_none;
+}
+
 static inline struct btree_write *btree_current_write(struct btree *b)
 {
        return b->writes + btree_node_write_idx(b);
index 340812b28d08d7467b71982b5e44a645bb24ff47..e77584607f0d377b28db9053a26917c6353732be 100644 (file)
@@ -1138,6 +1138,13 @@ static void bch2_btree_update_done(struct btree_update *as, struct btree_trans *
                               start_time);
 }
 
+static const char * const btree_node_reawrite_reason_strs[] = {
+#define x(n)   #n,
+       BTREE_NODE_REWRITE_REASON()
+#undef x
+       NULL,
+};
+
 static struct btree_update *
 bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
                        unsigned level_start, bool split,
@@ -1235,7 +1242,7 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
        struct btree *b = btree_path_node(path, path->level);
        as->node_start  = b->data->min_key;
        as->node_end    = b->data->max_key;
-       as->node_needed_rewrite = btree_node_need_rewrite(b);
+       as->node_needed_rewrite = btree_node_rewrite_reason(b);
        as->node_written = b->written;
        as->node_sectors = btree_buf_bytes(b) >> 9;
        as->node_remaining = __bch2_btree_u64s_remaining(b,
@@ -2699,11 +2706,11 @@ static void bch2_btree_update_to_text(struct printbuf *out, struct btree_update
        bch2_bpos_to_text(out, as->node_start);
        prt_char(out, ' ');
        bch2_bpos_to_text(out, as->node_end);
-       prt_printf(out, "\nwritten %u/%u u64s_remaining %u need_rewrite %u",
+       prt_printf(out, "\nwritten %u/%u u64s_remaining %u need_rewrite %s",
                   as->node_written,
                   as->node_sectors,
                   as->node_remaining,
-                  as->node_needed_rewrite);
+                  btree_node_reawrite_reason_strs[as->node_needed_rewrite]);
 
        prt_printf(out, "\nmode=%s nodes_written=%u cl.remaining=%u journal_seq=%llu\n",
                   bch2_btree_update_modes[as->mode],
index 85682a13de4dcd198f3b10611e3074eb84a45eff..b649c36c3fbb70c613e92d389ef7b1717461fbaa 100644 (file)
@@ -59,7 +59,7 @@ struct btree_update {
        enum btree_id                   btree_id;
        struct bpos                     node_start;
        struct bpos                     node_end;
-       bool                            node_needed_rewrite;
+       enum btree_node_rewrite_reason  node_needed_rewrite;
        u16                             node_written;
        u16                             node_sectors;
        u16                             node_remaining;