Commit | Line | Data |
---|---|---|
1c6fdbd8 KO |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include "bcachefs.h" | |
a6f4794f | 3 | #include "btree_cache.h" |
a850bde6 | 4 | #include "btree_iter.h" |
1c6fdbd8 | 5 | #include "error.h" |
b3c7fd35 | 6 | #include "journal.h" |
4fcd4de0 | 7 | #include "namei.h" |
d2554263 | 8 | #include "recovery_passes.h" |
1c6fdbd8 | 9 | #include "super.h" |
96f37eab | 10 | #include "thread_with_file.h" |
1c6fdbd8 | 11 | |
89b05118 KO |
12 | #define FSCK_ERR_RATELIMIT_NR 10 |
13 | ||
b42fac04 | 14 | void __bch2_log_msg_start(const char *fs_or_dev_name, struct printbuf *out) |
b00750c2 KO |
15 | { |
16 | printbuf_indent_add_nextline(out, 2); | |
17 | ||
18 | #ifdef BCACHEFS_LOG_PREFIX | |
b42fac04 | 19 | prt_printf(out, "bcachefs (%s): ", fs_or_dev_name); |
b00750c2 KO |
20 | #endif |
21 | } | |
22 | ||
23 | bool __bch2_inconsistent_error(struct bch_fs *c, struct printbuf *out) | |
1c6fdbd8 | 24 | { |
3c471b65 | 25 | set_bit(BCH_FS_error, &c->flags); |
1c6fdbd8 KO |
26 | |
27 | switch (c->opts.errors) { | |
2436cb9f | 28 | case BCH_ON_ERROR_continue: |
1c6fdbd8 | 29 | return false; |
33dfafa9 | 30 | case BCH_ON_ERROR_fix_safe: |
2436cb9f | 31 | case BCH_ON_ERROR_ro: |
b42fac04 | 32 | bch2_fs_emergency_read_only2(c, out); |
1c6fdbd8 | 33 | return true; |
2436cb9f | 34 | case BCH_ON_ERROR_panic: |
ebf561b2 | 35 | bch2_print_str(c, KERN_ERR, out->buf); |
1c6fdbd8 KO |
36 | panic(bch2_fmt(c, "panic after error")); |
37 | return true; | |
38 | default: | |
39 | BUG(); | |
40 | } | |
41 | } | |
42 | ||
b00750c2 KO |
43 | bool bch2_inconsistent_error(struct bch_fs *c) |
44 | { | |
45 | struct printbuf buf = PRINTBUF; | |
b2ffadcc KO |
46 | buf.atomic++; |
47 | ||
b00750c2 KO |
48 | printbuf_indent_add_nextline(&buf, 2); |
49 | ||
50 | bool ret = __bch2_inconsistent_error(c, &buf); | |
51 | if (ret) | |
52 | bch_err(c, "%s", buf.buf); | |
53 | printbuf_exit(&buf); | |
54 | return ret; | |
55 | } | |
56 | ||
57 | __printf(3, 0) | |
58 | static bool bch2_fs_trans_inconsistent(struct bch_fs *c, struct btree_trans *trans, | |
59 | const char *fmt, va_list args) | |
60 | { | |
61 | struct printbuf buf = PRINTBUF; | |
b2ffadcc | 62 | buf.atomic++; |
b00750c2 KO |
63 | |
64 | bch2_log_msg_start(c, &buf); | |
65 | ||
66 | prt_vprintf(&buf, fmt, args); | |
67 | prt_newline(&buf); | |
68 | ||
69 | if (trans) | |
70 | bch2_trans_updates_to_text(&buf, trans); | |
71 | bool ret = __bch2_inconsistent_error(c, &buf); | |
0acb385e | 72 | bch2_print_str(c, KERN_ERR, buf.buf); |
b00750c2 KO |
73 | |
74 | printbuf_exit(&buf); | |
75 | return ret; | |
76 | } | |
77 | ||
78 | bool bch2_fs_inconsistent(struct bch_fs *c, const char *fmt, ...) | |
79 | { | |
80 | va_list args; | |
81 | va_start(args, fmt); | |
82 | bool ret = bch2_fs_trans_inconsistent(c, NULL, fmt, args); | |
83 | va_end(args); | |
84 | return ret; | |
85 | } | |
86 | ||
87 | bool bch2_trans_inconsistent(struct btree_trans *trans, const char *fmt, ...) | |
88 | { | |
89 | va_list args; | |
90 | va_start(args, fmt); | |
91 | bool ret = bch2_fs_trans_inconsistent(trans->c, trans, fmt, args); | |
92 | va_end(args); | |
93 | return ret; | |
94 | } | |
95 | ||
6d77ce4a | 96 | int __bch2_topology_error(struct bch_fs *c, struct printbuf *out) |
aae15aaf | 97 | { |
6d77ce4a KO |
98 | prt_printf(out, "btree topology error: "); |
99 | ||
3c471b65 | 100 | set_bit(BCH_FS_topology_error, &c->flags); |
367cad09 | 101 | if (!test_bit(BCH_FS_in_recovery, &c->flags)) { |
6d77ce4a | 102 | __bch2_inconsistent_error(c, out); |
09b9c72b | 103 | return bch_err_throw(c, btree_need_topology_repair); |
52946d82 | 104 | } else { |
d4b30ed9 | 105 | return bch2_run_explicit_recovery_pass(c, out, BCH_RECOVERY_PASS_check_topology, 0) ?: |
14dd9564 | 106 | bch_err_throw(c, btree_need_topology_repair); |
52946d82 | 107 | } |
aae15aaf KO |
108 | } |
109 | ||
b00750c2 KO |
110 | int bch2_fs_topology_error(struct bch_fs *c, const char *fmt, ...) |
111 | { | |
112 | struct printbuf buf = PRINTBUF; | |
113 | ||
114 | bch2_log_msg_start(c, &buf); | |
115 | ||
116 | va_list args; | |
117 | va_start(args, fmt); | |
118 | prt_vprintf(&buf, fmt, args); | |
119 | va_end(args); | |
120 | ||
121 | int ret = __bch2_topology_error(c, &buf); | |
ebf561b2 | 122 | bch2_print_str(c, KERN_ERR, buf.buf); |
b00750c2 KO |
123 | |
124 | printbuf_exit(&buf); | |
125 | return ret; | |
126 | } | |
127 | ||
1c6fdbd8 KO |
128 | void bch2_fatal_error(struct bch_fs *c) |
129 | { | |
130 | if (bch2_fs_emergency_read_only(c)) | |
b74b147d | 131 | bch_err(c, "fatal error - emergency read only"); |
1c6fdbd8 KO |
132 | } |
133 | ||
134 | void bch2_io_error_work(struct work_struct *work) | |
135 | { | |
136 | struct bch_dev *ca = container_of(work, struct bch_dev, io_error_work); | |
137 | struct bch_fs *c = ca->fs; | |
981e3801 KO |
138 | |
139 | /* XXX: if it's reads or checksums that are failing, set it to failed */ | |
1c6fdbd8 | 140 | |
1ada1606 | 141 | down_write(&c->state_lock); |
981e3801 KO |
142 | unsigned long write_errors_start = READ_ONCE(ca->write_errors_start); |
143 | ||
144 | if (write_errors_start && | |
145 | time_after(jiffies, | |
146 | write_errors_start + c->opts.write_error_timeout * HZ)) { | |
147 | if (ca->mi.state >= BCH_MEMBER_STATE_ro) | |
148 | goto out; | |
149 | ||
150 | bool dev = !__bch2_dev_set_state(c, ca, BCH_MEMBER_STATE_ro, | |
151 | BCH_FORCE_IF_DEGRADED); | |
b42fac04 KO |
152 | struct printbuf buf = PRINTBUF; |
153 | __bch2_log_msg_start(ca->name, &buf); | |
981e3801 | 154 | |
b42fac04 | 155 | prt_printf(&buf, "writes erroring for %u seconds, setting %s ro", |
981e3801 | 156 | c->opts.write_error_timeout, |
1c6fdbd8 | 157 | dev ? "device" : "filesystem"); |
981e3801 | 158 | if (!dev) |
b42fac04 | 159 | bch2_fs_emergency_read_only2(c, &buf); |
981e3801 | 160 | |
b42fac04 KO |
161 | bch2_print_str(c, KERN_ERR, buf.buf); |
162 | printbuf_exit(&buf); | |
981e3801 KO |
163 | } |
164 | out: | |
1ada1606 | 165 | up_write(&c->state_lock); |
1c6fdbd8 KO |
166 | } |
167 | ||
94119eeb | 168 | void bch2_io_error(struct bch_dev *ca, enum bch_member_error_type type) |
1c6fdbd8 | 169 | { |
94119eeb | 170 | atomic64_inc(&ca->errors[type]); |
981e3801 KO |
171 | |
172 | if (type == BCH_MEMBER_ERROR_write && !ca->write_errors_start) | |
173 | ca->write_errors_start = jiffies; | |
174 | ||
175 | queue_work(system_long_wq, &ca->io_error_work); | |
1c6fdbd8 KO |
176 | } |
177 | ||
853b7393 KO |
178 | enum ask_yn { |
179 | YN_NO, | |
180 | YN_YES, | |
181 | YN_ALLNO, | |
182 | YN_ALLYES, | |
183 | }; | |
184 | ||
96f37eab KO |
185 | static enum ask_yn parse_yn_response(char *buf) |
186 | { | |
187 | buf = strim(buf); | |
188 | ||
189 | if (strlen(buf) == 1) | |
190 | switch (buf[0]) { | |
191 | case 'n': | |
192 | return YN_NO; | |
193 | case 'y': | |
194 | return YN_YES; | |
195 | case 'N': | |
196 | return YN_ALLNO; | |
197 | case 'Y': | |
198 | return YN_ALLYES; | |
199 | } | |
200 | return -1; | |
201 | } | |
202 | ||
1c6fdbd8 | 203 | #ifdef __KERNEL__ |
889fb3dc | 204 | static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c, struct btree_trans *trans) |
96f37eab KO |
205 | { |
206 | struct stdio_redirect *stdio = c->stdio; | |
207 | ||
208 | if (c->stdio_filter && c->stdio_filter != current) | |
209 | stdio = NULL; | |
210 | ||
211 | if (!stdio) | |
212 | return YN_NO; | |
213 | ||
889fb3dc KO |
214 | if (trans) |
215 | bch2_trans_unlock(trans); | |
216 | ||
217 | unsigned long unlock_long_at = trans ? jiffies + HZ * 2 : 0; | |
0c97c437 | 218 | darray_char line = {}; |
96f37eab KO |
219 | int ret; |
220 | ||
221 | do { | |
889fb3dc | 222 | unsigned long t; |
96f37eab | 223 | bch2_print(c, " (y,n, or Y,N for all errors of this type) "); |
889fb3dc KO |
224 | rewait: |
225 | t = unlock_long_at | |
226 | ? max_t(long, unlock_long_at - jiffies, 0) | |
227 | : MAX_SCHEDULE_TIMEOUT; | |
228 | ||
229 | int r = bch2_stdio_redirect_readline_timeout(stdio, &line, t); | |
230 | if (r == -ETIME) { | |
231 | bch2_trans_unlock_long(trans); | |
232 | unlock_long_at = 0; | |
233 | goto rewait; | |
234 | } | |
96f37eab | 235 | |
0c97c437 KO |
236 | if (r < 0) { |
237 | ret = YN_NO; | |
238 | break; | |
239 | } | |
889fb3dc | 240 | |
0c97c437 KO |
241 | darray_last(line) = '\0'; |
242 | } while ((ret = parse_yn_response(line.data)) < 0); | |
96f37eab | 243 | |
0c97c437 | 244 | darray_exit(&line); |
96f37eab KO |
245 | return ret; |
246 | } | |
1c6fdbd8 | 247 | #else |
853b7393 | 248 | |
1c6fdbd8 | 249 | #include "tools-util.h" |
853b7393 | 250 | |
889fb3dc | 251 | static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c, struct btree_trans *trans) |
853b7393 KO |
252 | { |
253 | char *buf = NULL; | |
254 | size_t buflen = 0; | |
96f37eab | 255 | int ret; |
853b7393 | 256 | |
96f37eab | 257 | do { |
4f2c166e | 258 | fputs(" (y,n, or Y,N for all errors of this type) ", stdout); |
853b7393 KO |
259 | fflush(stdout); |
260 | ||
261 | if (getline(&buf, &buflen, stdin) < 0) | |
262 | die("error reading from standard input"); | |
96f37eab | 263 | } while ((ret = parse_yn_response(buf)) < 0); |
853b7393 KO |
264 | |
265 | free(buf); | |
266 | return ret; | |
267 | } | |
268 | ||
1c6fdbd8 KO |
269 | #endif |
270 | ||
7337f9f1 KO |
271 | static struct fsck_err_state *fsck_err_get(struct bch_fs *c, |
272 | enum bch_sb_error_id id) | |
1c6fdbd8 | 273 | { |
dbb9936b | 274 | struct fsck_err_state *s; |
1c6fdbd8 | 275 | |
f5d26fa3 | 276 | list_for_each_entry(s, &c->fsck_error_msgs, list) |
7337f9f1 | 277 | if (s->id == id) { |
dbb9936b KO |
278 | /* |
279 | * move it to the head of the list: repeated fsck errors | |
280 | * are common | |
281 | */ | |
f5d26fa3 | 282 | list_move(&s->list, &c->fsck_error_msgs); |
dbb9936b KO |
283 | return s; |
284 | } | |
1c6fdbd8 | 285 | |
beb6db68 | 286 | s = kzalloc(sizeof(*s), GFP_NOFS); |
1c6fdbd8 | 287 | if (!s) { |
f5d26fa3 | 288 | if (!c->fsck_alloc_msgs_err) |
1c6fdbd8 | 289 | bch_err(c, "kmalloc err, cannot ratelimit fsck errs"); |
f5d26fa3 | 290 | c->fsck_alloc_msgs_err = true; |
dbb9936b | 291 | return NULL; |
1c6fdbd8 KO |
292 | } |
293 | ||
294 | INIT_LIST_HEAD(&s->list); | |
7337f9f1 | 295 | s->id = id; |
f5d26fa3 | 296 | list_add(&s->list, &c->fsck_error_msgs); |
dbb9936b KO |
297 | return s; |
298 | } | |
299 | ||
19391b92 KO |
300 | /* s/fix?/fixing/ s/recreate?/recreating/ */ |
301 | static void prt_actioning(struct printbuf *out, const char *action) | |
302 | { | |
303 | unsigned len = strlen(action); | |
304 | ||
305 | BUG_ON(action[len - 1] != '?'); | |
306 | --len; | |
307 | ||
308 | if (action[len - 1] == 'e') | |
309 | --len; | |
310 | ||
311 | prt_bytes(out, action, len); | |
312 | prt_str(out, "ing"); | |
313 | } | |
314 | ||
33dfafa9 KO |
315 | static const u8 fsck_flags_extra[] = { |
316 | #define x(t, n, flags) [BCH_FSCK_ERR_##t] = flags, | |
317 | BCH_SB_ERRS() | |
318 | #undef x | |
319 | }; | |
320 | ||
8b105909 KO |
321 | static int do_fsck_ask_yn(struct bch_fs *c, |
322 | struct btree_trans *trans, | |
323 | struct printbuf *question, | |
324 | const char *action) | |
325 | { | |
326 | prt_str(question, ", "); | |
327 | prt_str(question, action); | |
328 | ||
329 | if (bch2_fs_stdio_redirect(c)) | |
330 | bch2_print(c, "%s", question->buf); | |
331 | else | |
ebf561b2 | 332 | bch2_print_str(c, KERN_ERR, question->buf); |
8b105909 KO |
333 | |
334 | int ask = bch2_fsck_ask_yn(c, trans); | |
335 | ||
336 | if (trans) { | |
337 | int ret = bch2_trans_relock(trans); | |
338 | if (ret) | |
339 | return ret; | |
340 | } | |
341 | ||
342 | return ask; | |
343 | } | |
344 | ||
7337f9f1 KO |
345 | static struct fsck_err_state *count_fsck_err_locked(struct bch_fs *c, |
346 | enum bch_sb_error_id id, const char *msg, | |
347 | bool *repeat, bool *print, bool *suppress) | |
348 | { | |
349 | bch2_sb_error_count(c, id); | |
350 | ||
351 | struct fsck_err_state *s = fsck_err_get(c, id); | |
352 | if (s) { | |
353 | /* | |
354 | * We may be called multiple times for the same error on | |
355 | * transaction restart - this memoizes instead of asking the user | |
356 | * multiple times for the same error: | |
357 | */ | |
358 | if (s->last_msg && !strcmp(msg, s->last_msg)) { | |
359 | *repeat = true; | |
360 | *print = false; | |
361 | return s; | |
362 | } | |
363 | ||
364 | kfree(s->last_msg); | |
365 | s->last_msg = kstrdup(msg, GFP_KERNEL); | |
366 | ||
367 | if (c->opts.ratelimit_errors && | |
368 | s->nr >= FSCK_ERR_RATELIMIT_NR) { | |
369 | if (s->nr == FSCK_ERR_RATELIMIT_NR) | |
370 | *suppress = true; | |
371 | else | |
372 | *print = false; | |
373 | } | |
374 | ||
375 | s->nr++; | |
376 | } | |
377 | return s; | |
378 | } | |
379 | ||
20853251 KO |
380 | bool __bch2_count_fsck_err(struct bch_fs *c, |
381 | enum bch_sb_error_id id, struct printbuf *msg) | |
7337f9f1 KO |
382 | { |
383 | bch2_sb_error_count(c, id); | |
384 | ||
385 | mutex_lock(&c->fsck_error_msgs_lock); | |
20853251 KO |
386 | bool print = true, repeat = false, suppress = false; |
387 | ||
388 | count_fsck_err_locked(c, id, msg->buf, &repeat, &print, &suppress); | |
7337f9f1 | 389 | mutex_unlock(&c->fsck_error_msgs_lock); |
20853251 KO |
390 | |
391 | if (suppress) | |
392 | prt_printf(msg, "Ratelimiting new instances of previous error\n"); | |
393 | ||
394 | return print && !repeat; | |
7337f9f1 KO |
395 | } |
396 | ||
d31f1559 KO |
397 | int bch2_fsck_err_opt(struct bch_fs *c, |
398 | enum bch_fsck_flags flags, | |
399 | enum bch_sb_error_id err) | |
400 | { | |
401 | if (!WARN_ON(err >= ARRAY_SIZE(fsck_flags_extra))) | |
402 | flags |= fsck_flags_extra[err]; | |
403 | ||
367cad09 | 404 | if (test_bit(BCH_FS_in_fsck, &c->flags)) { |
d31f1559 | 405 | if (!(flags & (FSCK_CAN_FIX|FSCK_CAN_IGNORE))) |
09b9c72b | 406 | return bch_err_throw(c, fsck_repair_unimplemented); |
d31f1559 KO |
407 | |
408 | switch (c->opts.fix_errors) { | |
409 | case FSCK_FIX_exit: | |
09b9c72b | 410 | return bch_err_throw(c, fsck_errors_not_fixed); |
d31f1559 KO |
411 | case FSCK_FIX_yes: |
412 | if (flags & FSCK_CAN_FIX) | |
09b9c72b | 413 | return bch_err_throw(c, fsck_fix); |
d31f1559 KO |
414 | fallthrough; |
415 | case FSCK_FIX_no: | |
416 | if (flags & FSCK_CAN_IGNORE) | |
09b9c72b KO |
417 | return bch_err_throw(c, fsck_ignore); |
418 | return bch_err_throw(c, fsck_errors_not_fixed); | |
d31f1559 KO |
419 | case FSCK_FIX_ask: |
420 | if (flags & FSCK_AUTOFIX) | |
09b9c72b KO |
421 | return bch_err_throw(c, fsck_fix); |
422 | return bch_err_throw(c, fsck_ask); | |
d31f1559 KO |
423 | default: |
424 | BUG(); | |
425 | } | |
426 | } else { | |
427 | if ((flags & FSCK_AUTOFIX) && | |
428 | (c->opts.errors == BCH_ON_ERROR_continue || | |
429 | c->opts.errors == BCH_ON_ERROR_fix_safe)) | |
09b9c72b | 430 | return bch_err_throw(c, fsck_fix); |
d31f1559 KO |
431 | |
432 | if (c->opts.errors == BCH_ON_ERROR_continue && | |
433 | (flags & FSCK_CAN_IGNORE)) | |
09b9c72b KO |
434 | return bch_err_throw(c, fsck_ignore); |
435 | return bch_err_throw(c, fsck_errors_not_fixed); | |
d31f1559 KO |
436 | } |
437 | } | |
438 | ||
a850bde6 KO |
439 | int __bch2_fsck_err(struct bch_fs *c, |
440 | struct btree_trans *trans, | |
b65db750 KO |
441 | enum bch_fsck_flags flags, |
442 | enum bch_sb_error_id err, | |
443 | const char *fmt, ...) | |
dbb9936b | 444 | { |
dbb9936b | 445 | va_list args; |
dbb9936b | 446 | struct printbuf buf = PRINTBUF, *out = &buf; |
642c1aab | 447 | int ret = 0; |
19391b92 | 448 | const char *action_orig = "fix?", *action = action_orig; |
dbb9936b | 449 | |
e76a2b65 KO |
450 | might_sleep(); |
451 | ||
33dfafa9 KO |
452 | if (!WARN_ON(err >= ARRAY_SIZE(fsck_flags_extra))) |
453 | flags |= fsck_flags_extra[err]; | |
454 | ||
a850bde6 KO |
455 | if (!c) |
456 | c = trans->c; | |
457 | ||
5612daaf KO |
458 | /* |
459 | * Ugly: if there's a transaction in the current task it has to be | |
460 | * passed in to unlock if we prompt for user input. | |
461 | * | |
462 | * But, plumbing a transaction and transaction restarts into | |
463 | * bkey_validate() is problematic. | |
464 | * | |
465 | * So: | |
466 | * - make all bkey errors AUTOFIX, they're simple anyways (we just | |
467 | * delete the key) | |
468 | * - and we don't need to warn if we're not prompting | |
469 | */ | |
eb5db64c KO |
470 | WARN_ON((flags & FSCK_CAN_FIX) && |
471 | !(flags & FSCK_AUTOFIX) && | |
472 | !trans && | |
473 | bch2_current_has_btree_trans(c)); | |
a850bde6 | 474 | |
c8e58813 KO |
475 | if (test_bit(err, c->sb.errors_silent)) |
476 | return flags & FSCK_CAN_FIX | |
09b9c72b KO |
477 | ? bch_err_throw(c, fsck_fix) |
478 | : bch_err_throw(c, fsck_ignore); | |
8b16413c | 479 | |
1ece5323 KO |
480 | printbuf_indent_add_nextline(out, 2); |
481 | ||
482 | #ifdef BCACHEFS_LOG_PREFIX | |
483 | if (strncmp(fmt, "bcachefs", 8)) | |
484 | prt_printf(out, bch2_log_msg(c, "")); | |
485 | #endif | |
486 | ||
9c5d38bb KO |
487 | va_start(args, fmt); |
488 | prt_vprintf(out, fmt, args); | |
489 | va_end(args); | |
490 | ||
19391b92 KO |
491 | /* Custom fix/continue/recreate/etc.? */ |
492 | if (out->buf[out->pos - 1] == '?') { | |
493 | const char *p = strrchr(out->buf, ','); | |
494 | if (p) { | |
495 | out->pos = p - out->buf; | |
496 | action = kstrdup(p + 2, GFP_KERNEL); | |
497 | if (!action) { | |
498 | ret = -ENOMEM; | |
499 | goto err; | |
500 | } | |
501 | } | |
502 | } | |
503 | ||
f5d26fa3 | 504 | mutex_lock(&c->fsck_error_msgs_lock); |
7337f9f1 KO |
505 | bool repeat = false, print = true, suppress = false; |
506 | bool inconsistent = false, exiting = false; | |
507 | struct fsck_err_state *s = | |
508 | count_fsck_err_locked(c, err, buf.buf, &repeat, &print, &suppress); | |
509 | if (repeat) { | |
510 | ret = s->ret; | |
511 | goto err_unlock; | |
e2ee3eaa | 512 | } |
dbb9936b | 513 | |
052210c3 | 514 | if ((flags & FSCK_AUTOFIX) && |
33dfafa9 KO |
515 | (c->opts.errors == BCH_ON_ERROR_continue || |
516 | c->opts.errors == BCH_ON_ERROR_fix_safe)) { | |
517 | prt_str(out, ", "); | |
052210c3 KO |
518 | if (flags & FSCK_CAN_FIX) { |
519 | prt_actioning(out, action); | |
09b9c72b | 520 | ret = bch_err_throw(c, fsck_fix); |
052210c3 KO |
521 | } else { |
522 | prt_str(out, ", continuing"); | |
09b9c72b | 523 | ret = bch_err_throw(c, fsck_ignore); |
052210c3 KO |
524 | } |
525 | ||
526 | goto print; | |
367cad09 | 527 | } else if (!test_bit(BCH_FS_in_fsck, &c->flags)) { |
dbb9936b KO |
528 | if (c->opts.errors != BCH_ON_ERROR_continue || |
529 | !(flags & (FSCK_CAN_FIX|FSCK_CAN_IGNORE))) { | |
e5a3b8cf KO |
530 | prt_str_indented(out, ", shutting down\n" |
531 | "error not marked as autofix and not in fsck\n" | |
532 | "run fsck, and forward to devs so error can be marked for self-healing"); | |
22f51621 | 533 | inconsistent = true; |
b00750c2 | 534 | print = true; |
09b9c72b | 535 | ret = bch_err_throw(c, fsck_errors_not_fixed); |
dbb9936b | 536 | } else if (flags & FSCK_CAN_FIX) { |
19391b92 KO |
537 | prt_str(out, ", "); |
538 | prt_actioning(out, action); | |
09b9c72b | 539 | ret = bch_err_throw(c, fsck_fix); |
dbb9936b KO |
540 | } else { |
541 | prt_str(out, ", continuing"); | |
09b9c72b | 542 | ret = bch_err_throw(c, fsck_ignore); |
dbb9936b | 543 | } |
a0f8faea | 544 | } else if (c->opts.fix_errors == FSCK_FIX_exit) { |
dbb9936b | 545 | prt_str(out, ", exiting"); |
09b9c72b | 546 | ret = bch_err_throw(c, fsck_errors_not_fixed); |
0bc166ff | 547 | } else if (flags & FSCK_CAN_FIX) { |
853b7393 KO |
548 | int fix = s && s->fix |
549 | ? s->fix | |
550 | : c->opts.fix_errors; | |
551 | ||
a0f8faea | 552 | if (fix == FSCK_FIX_ask) { |
dbb9936b | 553 | print = false; |
853b7393 | 554 | |
8b105909 KO |
555 | ret = do_fsck_ask_yn(c, trans, out, action); |
556 | if (ret < 0) | |
557 | goto err_unlock; | |
853b7393 | 558 | |
8b105909 KO |
559 | if (ret >= YN_ALLNO && s) |
560 | s->fix = ret == YN_ALLNO | |
a0f8faea KO |
561 | ? FSCK_FIX_no |
562 | : FSCK_FIX_yes; | |
853b7393 | 563 | |
8b105909 | 564 | ret = ret & 1 |
09b9c72b KO |
565 | ? bch_err_throw(c, fsck_fix) |
566 | : bch_err_throw(c, fsck_ignore); | |
a0f8faea | 567 | } else if (fix == FSCK_FIX_yes || |
1c6fdbd8 KO |
568 | (c->opts.nochanges && |
569 | !(flags & FSCK_CAN_IGNORE))) { | |
19391b92 KO |
570 | prt_str(out, ", "); |
571 | prt_actioning(out, action); | |
09b9c72b | 572 | ret = bch_err_throw(c, fsck_fix); |
1c6fdbd8 | 573 | } else { |
19391b92 KO |
574 | prt_str(out, ", not "); |
575 | prt_actioning(out, action); | |
09b9c72b | 576 | ret = bch_err_throw(c, fsck_ignore); |
642c1aab KO |
577 | } |
578 | } else { | |
579 | if (flags & FSCK_CAN_IGNORE) { | |
580 | prt_str(out, ", continuing"); | |
09b9c72b | 581 | ret = bch_err_throw(c, fsck_ignore); |
642c1aab KO |
582 | } else { |
583 | prt_str(out, " (repair unimplemented)"); | |
09b9c72b | 584 | ret = bch_err_throw(c, fsck_repair_unimplemented); |
1c6fdbd8 | 585 | } |
1c6fdbd8 KO |
586 | } |
587 | ||
642c1aab | 588 | if (bch2_err_matches(ret, BCH_ERR_fsck_ignore) && |
a0f8faea | 589 | (c->opts.fix_errors == FSCK_FIX_exit || |
dbb9936b | 590 | !(flags & FSCK_CAN_IGNORE))) |
09b9c72b | 591 | ret = bch_err_throw(c, fsck_errors_not_fixed); |
dbb9936b | 592 | |
367cad09 | 593 | if (test_bit(BCH_FS_in_fsck, &c->flags) && |
642c1aab KO |
594 | (!bch2_err_matches(ret, BCH_ERR_fsck_fix) && |
595 | !bch2_err_matches(ret, BCH_ERR_fsck_ignore))) { | |
052210c3 | 596 | exiting = true; |
492e24d7 | 597 | print = true; |
052210c3 KO |
598 | } |
599 | print: | |
1ece5323 KO |
600 | prt_newline(out); |
601 | ||
602 | if (inconsistent) | |
b00750c2 | 603 | __bch2_inconsistent_error(c, out); |
1ece5323 KO |
604 | else if (exiting) |
605 | prt_printf(out, "Unable to continue, halting\n"); | |
7337f9f1 | 606 | else if (suppress) |
1ece5323 KO |
607 | prt_printf(out, "Ratelimiting new instances of previous error\n"); |
608 | ||
96f37eab | 609 | if (print) { |
b00750c2 KO |
610 | /* possibly strip an empty line, from printbuf_indent_add */ |
611 | while (out->pos && out->buf[out->pos - 1] == ' ') | |
612 | --out->pos; | |
613 | printbuf_nul_terminate(out); | |
614 | ||
96f37eab | 615 | if (bch2_fs_stdio_redirect(c)) |
b00750c2 | 616 | bch2_print(c, "%s", out->buf); |
96f37eab | 617 | else |
ebf561b2 | 618 | bch2_print_str(c, KERN_ERR, out->buf); |
96f37eab | 619 | } |
dbb9936b | 620 | |
9c5d38bb KO |
621 | if (s) |
622 | s->ret = ret; | |
b43f7249 | 623 | |
32a01cd4 KO |
624 | if (trans && |
625 | !(flags & FSCK_ERR_NO_LOG) && | |
626 | ret == -BCH_ERR_fsck_fix) | |
b43f7249 | 627 | ret = bch2_trans_log_str(trans, bch2_sb_error_strs[err]) ?: ret; |
642c1aab KO |
628 | err_unlock: |
629 | mutex_unlock(&c->fsck_error_msgs_lock); | |
630 | err: | |
eb73e777 KO |
631 | /* |
632 | * We don't yet track whether the filesystem currently has errors, for | |
633 | * log_fsck_err()s: that would require us to track for every error type | |
634 | * which recovery pass corrects it, to get the fsck exit status correct: | |
635 | */ | |
fec5e6f9 KO |
636 | if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) { |
637 | /* nothing */ | |
638 | } else if (bch2_err_matches(ret, BCH_ERR_fsck_fix)) { | |
642c1aab KO |
639 | set_bit(BCH_FS_errors_fixed, &c->flags); |
640 | } else { | |
641 | set_bit(BCH_FS_errors_not_fixed, &c->flags); | |
642 | set_bit(BCH_FS_error, &c->flags); | |
0bc166ff | 643 | } |
642c1aab | 644 | |
19391b92 KO |
645 | if (action != action_orig) |
646 | kfree(action); | |
647 | printbuf_exit(&buf); | |
642c1aab KO |
648 | |
649 | BUG_ON(!ret); | |
dbb9936b | 650 | return ret; |
1c6fdbd8 KO |
651 | } |
652 | ||
a6f4794f KO |
653 | static const char * const bch2_bkey_validate_contexts[] = { |
654 | #define x(n) #n, | |
655 | BKEY_VALIDATE_CONTEXTS() | |
656 | #undef x | |
657 | NULL | |
658 | }; | |
659 | ||
d97de0d0 KO |
660 | int __bch2_bkey_fsck_err(struct bch_fs *c, |
661 | struct bkey_s_c k, | |
a6f4794f | 662 | struct bkey_validate_context from, |
d97de0d0 KO |
663 | enum bch_sb_error_id err, |
664 | const char *fmt, ...) | |
665 | { | |
a6f4794f | 666 | if (from.flags & BCH_VALIDATE_silent) |
09b9c72b | 667 | return bch_err_throw(c, fsck_delete_bkey); |
658c82f4 KO |
668 | |
669 | unsigned fsck_flags = 0; | |
1302eeb7 KO |
670 | if (!(from.flags & (BCH_VALIDATE_write|BCH_VALIDATE_commit))) { |
671 | if (test_bit(err, c->sb.errors_silent)) | |
09b9c72b | 672 | return bch_err_throw(c, fsck_delete_bkey); |
1302eeb7 | 673 | |
658c82f4 | 674 | fsck_flags |= FSCK_AUTOFIX|FSCK_CAN_FIX; |
1302eeb7 KO |
675 | } |
676 | if (!WARN_ON(err >= ARRAY_SIZE(fsck_flags_extra))) | |
677 | fsck_flags |= fsck_flags_extra[err]; | |
658c82f4 | 678 | |
d97de0d0 | 679 | struct printbuf buf = PRINTBUF; |
60558d55 | 680 | prt_printf(&buf, "invalid bkey in %s", |
a6f4794f | 681 | bch2_bkey_validate_contexts[from.from]); |
60558d55 KO |
682 | |
683 | if (from.from == BKEY_VALIDATE_journal) | |
684 | prt_printf(&buf, " journal seq=%llu offset=%u", | |
685 | from.journal_seq, from.journal_offset); | |
686 | ||
687 | prt_str(&buf, " btree="); | |
a6f4794f KO |
688 | bch2_btree_id_to_text(&buf, from.btree); |
689 | prt_printf(&buf, " level=%u: ", from.level); | |
690 | ||
d97de0d0 | 691 | bch2_bkey_val_to_text(&buf, c, k); |
1ece5323 | 692 | prt_newline(&buf); |
1302eeb7 KO |
693 | |
694 | va_list args; | |
d97de0d0 KO |
695 | va_start(args, fmt); |
696 | prt_vprintf(&buf, fmt, args); | |
697 | va_end(args); | |
1302eeb7 | 698 | |
b00750c2 | 699 | int ret = __bch2_fsck_err(c, NULL, fsck_flags, err, "%s, delete?", buf.buf); |
d97de0d0 KO |
700 | printbuf_exit(&buf); |
701 | return ret; | |
702 | } | |
703 | ||
417f01e7 | 704 | static void __bch2_flush_fsck_errs(struct bch_fs *c, bool print) |
1c6fdbd8 KO |
705 | { |
706 | struct fsck_err_state *s, *n; | |
707 | ||
f5d26fa3 | 708 | mutex_lock(&c->fsck_error_msgs_lock); |
1c6fdbd8 | 709 | |
f5d26fa3 | 710 | list_for_each_entry_safe(s, n, &c->fsck_error_msgs, list) { |
417f01e7 | 711 | if (print && s->ratelimited && s->last_msg) |
1ece5323 | 712 | bch_err(c, "Saw %llu errors like:\n %s", s->nr, s->last_msg); |
1c6fdbd8 KO |
713 | |
714 | list_del(&s->list); | |
9c5d38bb | 715 | kfree(s->last_msg); |
1c6fdbd8 KO |
716 | kfree(s); |
717 | } | |
718 | ||
f5d26fa3 | 719 | mutex_unlock(&c->fsck_error_msgs_lock); |
1c6fdbd8 | 720 | } |
f7727a67 | 721 | |
417f01e7 KO |
722 | void bch2_flush_fsck_errs(struct bch_fs *c) |
723 | { | |
724 | __bch2_flush_fsck_errs(c, true); | |
725 | } | |
726 | ||
727 | void bch2_free_fsck_errs(struct bch_fs *c) | |
728 | { | |
729 | __bch2_flush_fsck_errs(c, false); | |
730 | } | |
731 | ||
06284963 KO |
732 | int bch2_inum_offset_err_msg_trans(struct btree_trans *trans, struct printbuf *out, |
733 | subvol_inum inum, u64 offset) | |
f7727a67 KO |
734 | { |
735 | u32 restart_count = trans->restart_count; | |
736 | int ret = 0; | |
737 | ||
06284963 KO |
738 | if (inum.subvol) { |
739 | ret = bch2_inum_to_path(trans, inum, out); | |
740 | if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) | |
741 | return ret; | |
742 | } | |
f7727a67 KO |
743 | if (!inum.subvol || ret) |
744 | prt_printf(out, "inum %llu:%llu", inum.subvol, inum.inum); | |
f7727a67 | 745 | prt_printf(out, " offset %llu: ", offset); |
f7727a67 | 746 | |
06284963 | 747 | return trans_was_restarted(trans, restart_count); |
f7727a67 KO |
748 | } |
749 | ||
750 | void bch2_inum_offset_err_msg(struct bch_fs *c, struct printbuf *out, | |
751 | subvol_inum inum, u64 offset) | |
752 | { | |
06284963 | 753 | bch2_trans_do(c, bch2_inum_offset_err_msg_trans(trans, out, inum, offset)); |
f7727a67 | 754 | } |
45f0e6c8 | 755 | |
06284963 KO |
756 | int bch2_inum_snap_offset_err_msg_trans(struct btree_trans *trans, struct printbuf *out, |
757 | struct bpos pos) | |
45f0e6c8 | 758 | { |
77aeaa2f KO |
759 | int ret = bch2_inum_snapshot_to_path(trans, pos.inode, pos.snapshot, NULL, out); |
760 | if (ret) | |
761 | return ret; | |
45f0e6c8 | 762 | |
45f0e6c8 | 763 | prt_printf(out, " offset %llu: ", pos.offset << 8); |
06284963 | 764 | return 0; |
45f0e6c8 | 765 | } |
1ccbcd32 KO |
766 | |
767 | void bch2_inum_snap_offset_err_msg(struct bch_fs *c, struct printbuf *out, | |
768 | struct bpos pos) | |
769 | { | |
770 | bch2_trans_do(c, bch2_inum_snap_offset_err_msg_trans(trans, out, pos)); | |
771 | } |