Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bcachefs: bch2_snapshot_is_ancestor() now safe to call in early recovery

this fixes an assertion pop in
bch2_check_snapshot_trees() ->
check_snapshot_tree() ->
bch2_snapshot_tree_master_subvol() ->
bch2_snapshot_is_ancestor()

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>

+18 -14
+18 -14
fs/bcachefs/snapshot.c
··· 91 91 92 92 /* Snapshot nodes: */ 93 93 94 - static bool bch2_snapshot_is_ancestor_early(struct bch_fs *c, u32 id, u32 ancestor) 94 + static bool __bch2_snapshot_is_ancestor_early(struct snapshot_table *t, u32 id, u32 ancestor) 95 95 { 96 - struct snapshot_table *t; 97 - 98 - rcu_read_lock(); 99 - t = rcu_dereference(c->snapshots); 100 - 101 96 while (id && id < ancestor) 102 97 id = __snapshot_t(t, id)->parent; 98 + return id == ancestor; 99 + } 100 + 101 + static bool bch2_snapshot_is_ancestor_early(struct bch_fs *c, u32 id, u32 ancestor) 102 + { 103 + rcu_read_lock(); 104 + bool ret = __bch2_snapshot_is_ancestor_early(rcu_dereference(c->snapshots), id, ancestor); 103 105 rcu_read_unlock(); 104 106 105 - return id == ancestor; 107 + return ret; 106 108 } 107 109 108 110 static inline u32 get_ancestor_below(struct snapshot_table *t, u32 id, u32 ancestor) ··· 122 120 123 121 bool __bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ancestor) 124 122 { 125 - struct snapshot_table *t; 126 123 bool ret; 127 124 128 - EBUG_ON(c->recovery_pass_done <= BCH_RECOVERY_PASS_check_snapshots); 129 - 130 125 rcu_read_lock(); 131 - t = rcu_dereference(c->snapshots); 126 + struct snapshot_table *t = rcu_dereference(c->snapshots); 127 + 128 + if (unlikely(c->recovery_pass_done <= BCH_RECOVERY_PASS_check_snapshots)) { 129 + ret = __bch2_snapshot_is_ancestor_early(t, id, ancestor); 130 + goto out; 131 + } 132 132 133 133 while (id && id < ancestor - IS_ANCESTOR_BITMAP) 134 134 id = get_ancestor_below(t, id, ancestor); ··· 138 134 if (id && id < ancestor) { 139 135 ret = test_bit(ancestor - id - 1, __snapshot_t(t, id)->is_ancestor); 140 136 141 - EBUG_ON(ret != bch2_snapshot_is_ancestor_early(c, id, ancestor)); 137 + EBUG_ON(ret != __bch2_snapshot_is_ancestor_early(t, id, ancestor)); 142 138 } else { 143 139 ret = id == ancestor; 144 140 } 145 - 141 + out: 146 142 rcu_read_unlock(); 147 143 148 144 return ret; ··· 551 547 "snapshot tree points to missing subvolume:\n %s", 552 548 (printbuf_reset(&buf), 553 549 bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf)) || 554 - fsck_err_on(!bch2_snapshot_is_ancestor_early(c, 550 + fsck_err_on(!bch2_snapshot_is_ancestor(c, 555 551 le32_to_cpu(subvol.snapshot), 556 552 root_id), 557 553 c, snapshot_tree_to_wrong_subvol,