1 // SPDX-License-Identifier: GPL-2.0 2 3 #include "bcachefs.h" 4 #include "alloc_background.h" 5 #include "backpointers.h" 6 #include "btree_gc.h" 7 #include "btree_node_scan.h" 8 #include "ec.h" 9 #include "fsck.h" 10 #include "inode.h" 11 #include "journal.h" 12 #include "lru.h" 13 #include "logged_ops.h" 14 #include "rebalance.h" 15 #include "recovery.h" 16 #include "recovery_passes.h" 17 #include "snapshot.h" 18 #include "subvolume.h" 19 #include "super.h" 20 #include "super-io.h" 21 22 const char * const bch2_recovery_passes[] = { 23 #define x(_fn, ...) #_fn, 24 BCH_RECOVERY_PASSES() 25 #undef x 26 NULL 27 }; 28 29 static int bch2_check_allocations(struct bch_fs *c) 30 { 31 return bch2_gc(c, true, false); 32 } 33 34 static int bch2_set_may_go_rw(struct bch_fs *c) 35 { 36 struct journal_keys *keys = &c->journal_keys; 37 38 /* 39 * After we go RW, the journal keys buffer can't be modified (except for 40 * setting journal_key->overwritten: it will be accessed by multiple 41 * threads 42 */ 43 move_gap(keys, keys->nr); 44 45 set_bit(BCH_FS_may_go_rw, &c->flags); 46 47 if (keys->nr || c->opts.fsck || !c->sb.clean || c->recovery_passes_explicit) 48 return bch2_fs_read_write_early(c); 49 return 0; 50 } 51 52 struct recovery_pass_fn { 53 int (*fn)(struct bch_fs *); 54 unsigned when; 55 }; 56 57 static struct recovery_pass_fn recovery_pass_fns[] = { 58 #define x(_fn, _id, _when) { .fn = bch2_##_fn, .when = _when }, 59 BCH_RECOVERY_PASSES() 60 #undef x 61 }; 62 63 static const u8 passes_to_stable_map[] = { 64 #define x(n, id, ...) [BCH_RECOVERY_PASS_##n] = BCH_RECOVERY_PASS_STABLE_##n, 65 BCH_RECOVERY_PASSES() 66 #undef x 67 }; 68 69 static enum bch_recovery_pass_stable bch2_recovery_pass_to_stable(enum bch_recovery_pass pass) 70 { 71 return passes_to_stable_map[pass]; 72 } 73 74 u64 bch2_recovery_passes_to_stable(u64 v) 75 { 76 u64 ret = 0; 77 for (unsigned i = 0; i < ARRAY_SIZE(passes_to_stable_map); i++) 78 if (v & BIT_ULL(i)) 79 ret |= BIT_ULL(passes_to_stable_map[i]); 80 return ret; 81 } 82 83 u64 bch2_recovery_passes_from_stable(u64 v) 84 { 85 static const u8 map[] = { 86 #define x(n, id, ...) [BCH_RECOVERY_PASS_STABLE_##n] = BCH_RECOVERY_PASS_##n, 87 BCH_RECOVERY_PASSES() 88 #undef x 89 }; 90 91 u64 ret = 0; 92 for (unsigned i = 0; i < ARRAY_SIZE(map); i++) 93 if (v & BIT_ULL(i)) 94 ret |= BIT_ULL(map[i]); 95 return ret; 96 } 97 98 /* 99 * For when we need to rewind recovery passes and run a pass we skipped: 100 */ 101 int bch2_run_explicit_recovery_pass(struct bch_fs *c, 102 enum bch_recovery_pass pass) 103 { 104 if (c->recovery_passes_explicit & BIT_ULL(pass)) 105 return 0; 106 107 bch_info(c, "running explicit recovery pass %s (%u), currently at %s (%u)", 108 bch2_recovery_passes[pass], pass, 109 bch2_recovery_passes[c->curr_recovery_pass], c->curr_recovery_pass); 110 111 c->recovery_passes_explicit |= BIT_ULL(pass); 112 113 if (c->curr_recovery_pass >= pass) { 114 c->curr_recovery_pass = pass; 115 c->recovery_passes_complete &= (1ULL << pass) >> 1; 116 return -BCH_ERR_restart_recovery; 117 } else { 118 return 0; 119 } 120 } 121 122 int bch2_run_explicit_recovery_pass_persistent(struct bch_fs *c, 123 enum bch_recovery_pass pass) 124 { 125 enum bch_recovery_pass_stable s = bch2_recovery_pass_to_stable(pass); 126 127 mutex_lock(&c->sb_lock); 128 struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext); 129 130 if (!test_bit_le64(s, ext->recovery_passes_required)) { 131 __set_bit_le64(s, ext->recovery_passes_required); 132 bch2_write_super(c); 133 } 134 mutex_unlock(&c->sb_lock); 135 136 return bch2_run_explicit_recovery_pass(c, pass); 137 } 138 139 static void bch2_clear_recovery_pass_required(struct bch_fs *c, 140 enum bch_recovery_pass pass) 141 { 142 enum bch_recovery_pass_stable s = bch2_recovery_pass_to_stable(pass); 143 144 mutex_lock(&c->sb_lock); 145 struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext); 146 147 if (test_bit_le64(s, ext->recovery_passes_required)) { 148 __clear_bit_le64(s, ext->recovery_passes_required); 149 bch2_write_super(c); 150 } 151 mutex_unlock(&c->sb_lock); 152 } 153 154 u64 bch2_fsck_recovery_passes(void) 155 { 156 u64 ret = 0; 157 158 for (unsigned i = 0; i < ARRAY_SIZE(recovery_pass_fns); i++) 159 if (recovery_pass_fns[i].when & PASS_FSCK) 160 ret |= BIT_ULL(i); 161 return ret; 162 } 163 164 static bool should_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pass) 165 { 166 struct recovery_pass_fn *p = recovery_pass_fns + pass; 167 168 if (c->recovery_passes_explicit & BIT_ULL(pass)) 169 return true; 170 if ((p->when & PASS_FSCK) && c->opts.fsck) 171 return true; 172 if ((p->when & PASS_UNCLEAN) && !c->sb.clean) 173 return true; 174 if (p->when & PASS_ALWAYS) 175 return true; 176 return false; 177 } 178 179 static int bch2_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pass) 180 { 181 struct recovery_pass_fn *p = recovery_pass_fns + pass; 182 int ret; 183 184 if (!(p->when & PASS_SILENT)) 185 bch2_print(c, KERN_INFO bch2_log_msg(c, "%s..."), 186 bch2_recovery_passes[pass]); 187 ret = p->fn(c); 188 if (ret) 189 return ret; 190 if (!(p->when & PASS_SILENT)) 191 bch2_print(c, KERN_CONT " done\n"); 192 193 return 0; 194 } 195 196 int bch2_run_online_recovery_passes(struct bch_fs *c) 197 { 198 int ret = 0; 199 200 for (unsigned i = 0; i < ARRAY_SIZE(recovery_pass_fns); i++) { 201 struct recovery_pass_fn *p = recovery_pass_fns + i; 202 203 if (!(p->when & PASS_ONLINE)) 204 continue; 205 206 ret = bch2_run_recovery_pass(c, i); 207 if (bch2_err_matches(ret, BCH_ERR_restart_recovery)) { 208 i = c->curr_recovery_pass; 209 continue; 210 } 211 if (ret) 212 break; 213 } 214 215 return ret; 216 } 217 218 int bch2_run_recovery_passes(struct bch_fs *c) 219 { 220 int ret = 0; 221 222 while (c->curr_recovery_pass < ARRAY_SIZE(recovery_pass_fns)) { 223 if (c->opts.recovery_pass_last && 224 c->curr_recovery_pass > c->opts.recovery_pass_last) 225 break; 226 227 if (should_run_recovery_pass(c, c->curr_recovery_pass)) { 228 unsigned pass = c->curr_recovery_pass; 229 230 ret = bch2_run_recovery_pass(c, c->curr_recovery_pass); 231 if (bch2_err_matches(ret, BCH_ERR_restart_recovery) || 232 (ret && c->curr_recovery_pass < pass)) 233 continue; 234 if (ret) 235 break; 236 237 c->recovery_passes_complete |= BIT_ULL(c->curr_recovery_pass); 238 } 239 240 c->recovery_pass_done = max(c->recovery_pass_done, c->curr_recovery_pass); 241 242 if (!test_bit(BCH_FS_error, &c->flags)) 243 bch2_clear_recovery_pass_required(c, c->curr_recovery_pass); 244 245 c->curr_recovery_pass++; 246 } 247 248 return ret; 249 } 250