xref: /linux/fs/bcachefs/recovery_passes.c (revision 1a20a9a0ddef17c0bd67eece34a7439b02a7b0ba)
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