Commit | Line | Data |
---|---|---|
1c6fdbd8 KO |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include "bcachefs.h" | |
3 | #include "error.h" | |
4 | #include "io.h" | |
5 | #include "super.h" | |
6 | ||
89b05118 KO |
7 | #define FSCK_ERR_RATELIMIT_NR 10 |
8 | ||
1c6fdbd8 KO |
9 | bool bch2_inconsistent_error(struct bch_fs *c) |
10 | { | |
11 | set_bit(BCH_FS_ERROR, &c->flags); | |
12 | ||
13 | switch (c->opts.errors) { | |
2436cb9f | 14 | case BCH_ON_ERROR_continue: |
1c6fdbd8 | 15 | return false; |
2436cb9f | 16 | case BCH_ON_ERROR_ro: |
1c6fdbd8 KO |
17 | if (bch2_fs_emergency_read_only(c)) |
18 | bch_err(c, "emergency read only"); | |
19 | return true; | |
2436cb9f | 20 | case BCH_ON_ERROR_panic: |
1c6fdbd8 KO |
21 | panic(bch2_fmt(c, "panic after error")); |
22 | return true; | |
23 | default: | |
24 | BUG(); | |
25 | } | |
26 | } | |
27 | ||
28 | void bch2_fatal_error(struct bch_fs *c) | |
29 | { | |
30 | if (bch2_fs_emergency_read_only(c)) | |
31 | bch_err(c, "emergency read only"); | |
32 | } | |
33 | ||
34 | void bch2_io_error_work(struct work_struct *work) | |
35 | { | |
36 | struct bch_dev *ca = container_of(work, struct bch_dev, io_error_work); | |
37 | struct bch_fs *c = ca->fs; | |
38 | bool dev; | |
39 | ||
1ada1606 | 40 | down_write(&c->state_lock); |
2436cb9f | 41 | dev = bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_ro, |
1c6fdbd8 KO |
42 | BCH_FORCE_IF_DEGRADED); |
43 | if (dev | |
2436cb9f | 44 | ? __bch2_dev_set_state(c, ca, BCH_MEMBER_STATE_ro, |
1c6fdbd8 KO |
45 | BCH_FORCE_IF_DEGRADED) |
46 | : bch2_fs_emergency_read_only(c)) | |
47 | bch_err(ca, | |
48 | "too many IO errors, setting %s RO", | |
49 | dev ? "device" : "filesystem"); | |
1ada1606 | 50 | up_write(&c->state_lock); |
1c6fdbd8 KO |
51 | } |
52 | ||
53 | void bch2_io_error(struct bch_dev *ca) | |
54 | { | |
55 | //queue_work(system_long_wq, &ca->io_error_work); | |
56 | } | |
57 | ||
58 | #ifdef __KERNEL__ | |
59 | #define ask_yn() false | |
60 | #else | |
61 | #include "tools-util.h" | |
62 | #endif | |
63 | ||
64 | enum fsck_err_ret bch2_fsck_err(struct bch_fs *c, unsigned flags, | |
65 | const char *fmt, ...) | |
66 | { | |
e2ee3eaa | 67 | struct fsck_err_state *s = NULL; |
1c6fdbd8 KO |
68 | va_list args; |
69 | bool fix = false, print = true, suppressing = false; | |
70 | char _buf[sizeof(s->buf)], *buf = _buf; | |
71 | ||
6543f562 KO |
72 | if (test_bit(BCH_FS_FSCK_DONE, &c->flags)) { |
73 | va_start(args, fmt); | |
74 | vprintk(fmt, args); | |
75 | va_end(args); | |
1c6fdbd8 | 76 | |
0bc166ff KO |
77 | return bch2_inconsistent_error(c) |
78 | ? FSCK_ERR_EXIT | |
79 | : FSCK_ERR_FIX; | |
6543f562 KO |
80 | } |
81 | ||
82 | mutex_lock(&c->fsck_error_lock); | |
1c6fdbd8 KO |
83 | |
84 | list_for_each_entry(s, &c->fsck_errors, list) | |
85 | if (s->fmt == fmt) | |
86 | goto found; | |
87 | ||
beb6db68 | 88 | s = kzalloc(sizeof(*s), GFP_NOFS); |
1c6fdbd8 KO |
89 | if (!s) { |
90 | if (!c->fsck_alloc_err) | |
91 | bch_err(c, "kmalloc err, cannot ratelimit fsck errs"); | |
92 | c->fsck_alloc_err = true; | |
93 | buf = _buf; | |
94 | goto print; | |
95 | } | |
96 | ||
97 | INIT_LIST_HEAD(&s->list); | |
98 | s->fmt = fmt; | |
99 | found: | |
100 | list_move(&s->list, &c->fsck_errors); | |
101 | s->nr++; | |
e2ee3eaa KO |
102 | if (c->opts.ratelimit_errors && |
103 | s->nr >= FSCK_ERR_RATELIMIT_NR) { | |
104 | if (s->nr == FSCK_ERR_RATELIMIT_NR) | |
105 | suppressing = true; | |
106 | else | |
107 | print = false; | |
108 | } | |
1c6fdbd8 KO |
109 | buf = s->buf; |
110 | print: | |
111 | va_start(args, fmt); | |
112 | vscnprintf(buf, sizeof(_buf), fmt, args); | |
113 | va_end(args); | |
114 | ||
115 | if (c->opts.fix_errors == FSCK_OPT_EXIT) { | |
116 | bch_err(c, "%s, exiting", buf); | |
0bc166ff | 117 | } else if (flags & FSCK_CAN_FIX) { |
1c6fdbd8 KO |
118 | if (c->opts.fix_errors == FSCK_OPT_ASK) { |
119 | printk(KERN_ERR "%s: fix?", buf); | |
120 | fix = ask_yn(); | |
121 | } else if (c->opts.fix_errors == FSCK_OPT_YES || | |
122 | (c->opts.nochanges && | |
123 | !(flags & FSCK_CAN_IGNORE))) { | |
124 | if (print) | |
125 | bch_err(c, "%s, fixing", buf); | |
126 | fix = true; | |
127 | } else { | |
128 | if (print) | |
129 | bch_err(c, "%s, not fixing", buf); | |
130 | fix = false; | |
131 | } | |
132 | } else if (flags & FSCK_NEED_FSCK) { | |
133 | if (print) | |
134 | bch_err(c, "%s (run fsck to correct)", buf); | |
135 | } else { | |
136 | if (print) | |
137 | bch_err(c, "%s (repair unimplemented)", buf); | |
138 | } | |
139 | ||
140 | if (suppressing) | |
141 | bch_err(c, "Ratelimiting new instances of previous error"); | |
142 | ||
143 | mutex_unlock(&c->fsck_error_lock); | |
144 | ||
0bc166ff KO |
145 | if (fix) { |
146 | set_bit(BCH_FS_ERRORS_FIXED, &c->flags); | |
147 | return FSCK_ERR_FIX; | |
148 | } else { | |
149 | set_bit(BCH_FS_ERROR, &c->flags); | |
150 | return c->opts.fix_errors == FSCK_OPT_EXIT || | |
151 | !(flags & FSCK_CAN_IGNORE) | |
152 | ? FSCK_ERR_EXIT | |
153 | : FSCK_ERR_IGNORE; | |
154 | } | |
1c6fdbd8 KO |
155 | } |
156 | ||
157 | void bch2_flush_fsck_errs(struct bch_fs *c) | |
158 | { | |
159 | struct fsck_err_state *s, *n; | |
160 | ||
161 | mutex_lock(&c->fsck_error_lock); | |
1c6fdbd8 KO |
162 | |
163 | list_for_each_entry_safe(s, n, &c->fsck_errors, list) { | |
e2ee3eaa | 164 | if (s->ratelimited) |
1c6fdbd8 KO |
165 | bch_err(c, "Saw %llu errors like:\n %s", s->nr, s->buf); |
166 | ||
167 | list_del(&s->list); | |
168 | kfree(s); | |
169 | } | |
170 | ||
171 | mutex_unlock(&c->fsck_error_lock); | |
172 | } |