1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _BCACHEFS_ERROR_H |
3 | #define _BCACHEFS_ERROR_H |
4 | |
5 | #include <linux/list.h> |
6 | #include <linux/printk.h> |
7 | #include "sb-errors.h" |
8 | |
9 | struct bch_dev; |
10 | struct bch_fs; |
11 | struct work_struct; |
12 | |
13 | /* |
14 | * XXX: separate out errors that indicate on disk data is inconsistent, and flag |
15 | * superblock as such |
16 | */ |
17 | |
18 | /* Error messages: */ |
19 | |
20 | /* |
21 | * Inconsistency errors: The on disk data is inconsistent. If these occur during |
22 | * initial recovery, they don't indicate a bug in the running code - we walk all |
23 | * the metadata before modifying anything. If they occur at runtime, they |
24 | * indicate either a bug in the running code or (less likely) data is being |
25 | * silently corrupted under us. |
26 | * |
27 | * XXX: audit all inconsistent errors and make sure they're all recoverable, in |
28 | * BCH_ON_ERROR_CONTINUE mode |
29 | */ |
30 | |
31 | bool bch2_inconsistent_error(struct bch_fs *); |
32 | |
33 | int bch2_topology_error(struct bch_fs *); |
34 | |
35 | #define bch2_fs_topology_error(c, ...) \ |
36 | ({ \ |
37 | bch_err(c, "btree topology error: " __VA_ARGS__); \ |
38 | bch2_topology_error(c); \ |
39 | }) |
40 | |
41 | #define bch2_fs_inconsistent(c, ...) \ |
42 | ({ \ |
43 | bch_err(c, __VA_ARGS__); \ |
44 | bch2_inconsistent_error(c); \ |
45 | }) |
46 | |
47 | #define bch2_fs_inconsistent_on(cond, c, ...) \ |
48 | ({ \ |
49 | bool _ret = unlikely(!!(cond)); \ |
50 | \ |
51 | if (_ret) \ |
52 | bch2_fs_inconsistent(c, __VA_ARGS__); \ |
53 | _ret; \ |
54 | }) |
55 | |
56 | /* |
57 | * Later we might want to mark only the particular device inconsistent, not the |
58 | * entire filesystem: |
59 | */ |
60 | |
61 | #define bch2_dev_inconsistent(ca, ...) \ |
62 | do { \ |
63 | bch_err(ca, __VA_ARGS__); \ |
64 | bch2_inconsistent_error((ca)->fs); \ |
65 | } while (0) |
66 | |
67 | #define bch2_dev_inconsistent_on(cond, ca, ...) \ |
68 | ({ \ |
69 | bool _ret = unlikely(!!(cond)); \ |
70 | \ |
71 | if (_ret) \ |
72 | bch2_dev_inconsistent(ca, __VA_ARGS__); \ |
73 | _ret; \ |
74 | }) |
75 | |
76 | /* |
77 | * When a transaction update discovers or is causing a fs inconsistency, it's |
78 | * helpful to also dump the pending updates: |
79 | */ |
80 | #define bch2_trans_inconsistent(trans, ...) \ |
81 | ({ \ |
82 | bch_err(trans->c, __VA_ARGS__); \ |
83 | bch2_dump_trans_updates(trans); \ |
84 | bch2_inconsistent_error(trans->c); \ |
85 | }) |
86 | |
87 | #define bch2_trans_inconsistent_on(cond, trans, ...) \ |
88 | ({ \ |
89 | bool _ret = unlikely(!!(cond)); \ |
90 | \ |
91 | if (_ret) \ |
92 | bch2_trans_inconsistent(trans, __VA_ARGS__); \ |
93 | _ret; \ |
94 | }) |
95 | |
96 | /* |
97 | * Fsck errors: inconsistency errors we detect at mount time, and should ideally |
98 | * be able to repair: |
99 | */ |
100 | |
101 | struct fsck_err_state { |
102 | struct list_head list; |
103 | const char *fmt; |
104 | u64 nr; |
105 | bool ratelimited; |
106 | int ret; |
107 | int fix; |
108 | char *last_msg; |
109 | }; |
110 | |
111 | enum bch_fsck_flags { |
112 | FSCK_CAN_FIX = 1 << 0, |
113 | FSCK_CAN_IGNORE = 1 << 1, |
114 | FSCK_NEED_FSCK = 1 << 2, |
115 | FSCK_NO_RATELIMIT = 1 << 3, |
116 | }; |
117 | |
118 | #define fsck_err_count(_c, _err) bch2_sb_err_count(_c, BCH_FSCK_ERR_##_err) |
119 | |
120 | __printf(4, 5) __cold |
121 | int bch2_fsck_err(struct bch_fs *, |
122 | enum bch_fsck_flags, |
123 | enum bch_sb_error_id, |
124 | const char *, ...); |
125 | void bch2_flush_fsck_errs(struct bch_fs *); |
126 | |
127 | #define __fsck_err(c, _flags, _err_type, ...) \ |
128 | ({ \ |
129 | int _ret = bch2_fsck_err(c, _flags, BCH_FSCK_ERR_##_err_type, \ |
130 | __VA_ARGS__); \ |
131 | \ |
132 | if (_ret != -BCH_ERR_fsck_fix && \ |
133 | _ret != -BCH_ERR_fsck_ignore) { \ |
134 | ret = _ret; \ |
135 | goto fsck_err; \ |
136 | } \ |
137 | \ |
138 | _ret == -BCH_ERR_fsck_fix; \ |
139 | }) |
140 | |
141 | /* These macros return true if error should be fixed: */ |
142 | |
143 | /* XXX: mark in superblock that filesystem contains errors, if we ignore: */ |
144 | |
145 | #define __fsck_err_on(cond, c, _flags, _err_type, ...) \ |
146 | (unlikely(cond) ? __fsck_err(c, _flags, _err_type, __VA_ARGS__) : false) |
147 | |
148 | #define need_fsck_err_on(cond, c, _err_type, ...) \ |
149 | __fsck_err_on(cond, c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, _err_type, __VA_ARGS__) |
150 | |
151 | #define need_fsck_err(c, _err_type, ...) \ |
152 | __fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, _err_type, __VA_ARGS__) |
153 | |
154 | #define mustfix_fsck_err(c, _err_type, ...) \ |
155 | __fsck_err(c, FSCK_CAN_FIX, _err_type, __VA_ARGS__) |
156 | |
157 | #define mustfix_fsck_err_on(cond, c, _err_type, ...) \ |
158 | __fsck_err_on(cond, c, FSCK_CAN_FIX, _err_type, __VA_ARGS__) |
159 | |
160 | #define fsck_err(c, _err_type, ...) \ |
161 | __fsck_err(c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, _err_type, __VA_ARGS__) |
162 | |
163 | #define fsck_err_on(cond, c, _err_type, ...) \ |
164 | __fsck_err_on(cond, c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, _err_type, __VA_ARGS__) |
165 | |
166 | __printf(4, 0) |
167 | static inline void bch2_bkey_fsck_err(struct bch_fs *c, |
168 | struct printbuf *err_msg, |
169 | enum bch_sb_error_id err_type, |
170 | const char *fmt, ...) |
171 | { |
172 | va_list args; |
173 | |
174 | va_start(args, fmt); |
175 | prt_vprintf(err_msg, fmt, args); |
176 | va_end(args); |
177 | } |
178 | |
179 | #define bkey_fsck_err(c, _err_msg, _err_type, ...) \ |
180 | do { \ |
181 | prt_printf(_err_msg, __VA_ARGS__); \ |
182 | bch2_sb_error_count(c, BCH_FSCK_ERR_##_err_type); \ |
183 | ret = -BCH_ERR_invalid_bkey; \ |
184 | goto fsck_err; \ |
185 | } while (0) |
186 | |
187 | #define bkey_fsck_err_on(cond, ...) \ |
188 | do { \ |
189 | if (unlikely(cond)) \ |
190 | bkey_fsck_err(__VA_ARGS__); \ |
191 | } while (0) |
192 | |
193 | /* |
194 | * Fatal errors: these don't indicate a bug, but we can't continue running in RW |
195 | * mode - pretty much just due to metadata IO errors: |
196 | */ |
197 | |
198 | void bch2_fatal_error(struct bch_fs *); |
199 | |
200 | #define bch2_fs_fatal_error(c, _msg, ...) \ |
201 | do { \ |
202 | bch_err(c, "%s(): fatal error " _msg, __func__, ##__VA_ARGS__); \ |
203 | bch2_fatal_error(c); \ |
204 | } while (0) |
205 | |
206 | #define bch2_fs_fatal_err_on(cond, c, ...) \ |
207 | ({ \ |
208 | bool _ret = unlikely(!!(cond)); \ |
209 | \ |
210 | if (_ret) \ |
211 | bch2_fs_fatal_error(c, __VA_ARGS__); \ |
212 | _ret; \ |
213 | }) |
214 | |
215 | /* |
216 | * IO errors: either recoverable metadata IO (because we have replicas), or data |
217 | * IO - we need to log it and print out a message, but we don't (necessarily) |
218 | * want to shut down the fs: |
219 | */ |
220 | |
221 | void bch2_io_error_work(struct work_struct *); |
222 | |
223 | /* Does the error handling without logging a message */ |
224 | void bch2_io_error(struct bch_dev *, enum bch_member_error_type); |
225 | |
226 | #define bch2_dev_io_err_on(cond, ca, _type, ...) \ |
227 | ({ \ |
228 | bool _ret = (cond); \ |
229 | \ |
230 | if (_ret) { \ |
231 | bch_err_dev_ratelimited(ca, __VA_ARGS__); \ |
232 | bch2_io_error(ca, _type); \ |
233 | } \ |
234 | _ret; \ |
235 | }) |
236 | |
237 | #define bch2_dev_inum_io_err_on(cond, ca, _type, ...) \ |
238 | ({ \ |
239 | bool _ret = (cond); \ |
240 | \ |
241 | if (_ret) { \ |
242 | bch_err_inum_offset_ratelimited(ca, __VA_ARGS__); \ |
243 | bch2_io_error(ca, _type); \ |
244 | } \ |
245 | _ret; \ |
246 | }) |
247 | |
248 | #endif /* _BCACHEFS_ERROR_H */ |
249 | |