xref: /linux/fs/bcachefs/error.h (revision ff0905bbf991f4337b5ebc19c0d43525ebb0d96b)
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 "bkey_types.h"
8 #include "sb-errors.h"
9 
10 struct bch_dev;
11 struct bch_fs;
12 struct work_struct;
13 
14 /*
15  * XXX: separate out errors that indicate on disk data is inconsistent, and flag
16  * superblock as such
17  */
18 
19 /* Error messages: */
20 
21 void __bch2_log_msg_start(const char *, struct printbuf *);
22 
bch2_log_msg_start(struct bch_fs * c,struct printbuf * out)23 static inline void bch2_log_msg_start(struct bch_fs *c, struct printbuf *out)
24 {
25 	__bch2_log_msg_start(c->name, out);
26 }
27 
28 /*
29  * Inconsistency errors: The on disk data is inconsistent. If these occur during
30  * initial recovery, they don't indicate a bug in the running code - we walk all
31  * the metadata before modifying anything. If they occur at runtime, they
32  * indicate either a bug in the running code or (less likely) data is being
33  * silently corrupted under us.
34  *
35  * XXX: audit all inconsistent errors and make sure they're all recoverable, in
36  * BCH_ON_ERROR_CONTINUE mode
37  */
38 
39 bool __bch2_inconsistent_error(struct bch_fs *, struct printbuf *);
40 bool bch2_inconsistent_error(struct bch_fs *);
41 __printf(2, 3)
42 bool bch2_fs_inconsistent(struct bch_fs *, const char *, ...);
43 
44 #define bch2_fs_inconsistent_on(cond, ...)				\
45 ({									\
46 	bool _ret = unlikely(!!(cond));					\
47 	if (_ret)							\
48 		bch2_fs_inconsistent(__VA_ARGS__);			\
49 	_ret;								\
50 })
51 
52 __printf(2, 3)
53 bool bch2_trans_inconsistent(struct btree_trans *, const char *, ...);
54 
55 #define bch2_trans_inconsistent_on(cond, ...)				\
56 ({									\
57 	bool _ret = unlikely(!!(cond));					\
58 	if (_ret)							\
59 		bch2_trans_inconsistent(__VA_ARGS__);			\
60 	_ret;								\
61 })
62 
63 int __bch2_topology_error(struct bch_fs *, struct printbuf *);
64 __printf(2, 3)
65 int bch2_fs_topology_error(struct bch_fs *, const char *, ...);
66 
67 /*
68  * Fsck errors: inconsistency errors we detect at mount time, and should ideally
69  * be able to repair:
70  */
71 
72 struct fsck_err_state {
73 	struct list_head	list;
74 	enum bch_sb_error_id	id;
75 	u64			nr;
76 	bool			ratelimited;
77 	int			ret;
78 	int			fix;
79 	char			*last_msg;
80 };
81 
82 #define fsck_err_count(_c, _err)	bch2_sb_err_count(_c, BCH_FSCK_ERR_##_err)
83 
84 bool __bch2_count_fsck_err(struct bch_fs *, enum bch_sb_error_id, struct printbuf *);
85 #define bch2_count_fsck_err(_c, _err, ...)				\
86 	__bch2_count_fsck_err(_c, BCH_FSCK_ERR_##_err, __VA_ARGS__)
87 
88 int bch2_fsck_err_opt(struct bch_fs *,
89 		      enum bch_fsck_flags,
90 		      enum bch_sb_error_id);
91 
92 __printf(5, 6) __cold
93 int __bch2_fsck_err(struct bch_fs *, struct btree_trans *,
94 		  enum bch_fsck_flags,
95 		  enum bch_sb_error_id,
96 		  const char *, ...);
97 #define bch2_fsck_err(c, _flags, _err_type, ...)				\
98 	__bch2_fsck_err(type_is(c, struct bch_fs *) ? (struct bch_fs *) c : NULL,\
99 			type_is(c, struct btree_trans *) ? (struct btree_trans *) c : NULL,\
100 			_flags, BCH_FSCK_ERR_##_err_type, __VA_ARGS__)
101 
102 void bch2_flush_fsck_errs(struct bch_fs *);
103 void bch2_free_fsck_errs(struct bch_fs *);
104 
105 #define fsck_err_wrap(_do)						\
106 ({									\
107 	int _ret = _do;							\
108 	if (!bch2_err_matches(_ret, BCH_ERR_fsck_fix) &&		\
109 	    !bch2_err_matches(_ret, BCH_ERR_fsck_ignore)) {		\
110 		ret = _ret;						\
111 		goto fsck_err;						\
112 	}								\
113 									\
114 	bch2_err_matches(_ret, BCH_ERR_fsck_fix);			\
115 })
116 
117 #define __fsck_err(...)		fsck_err_wrap(bch2_fsck_err(__VA_ARGS__))
118 
119 /* These macros return true if error should be fixed: */
120 
121 /* XXX: mark in superblock that filesystem contains errors, if we ignore: */
122 
123 #define __fsck_err_on(cond, c, _flags, _err_type, ...)			\
124 ({									\
125 	might_sleep();							\
126 									\
127 	if (type_is(c, struct bch_fs *))				\
128 		WARN_ON(bch2_current_has_btree_trans((struct bch_fs *) c));\
129 									\
130 	(unlikely(cond) ? __fsck_err(c, _flags, _err_type, __VA_ARGS__) : false);\
131 })
132 
133 #define mustfix_fsck_err(c, _err_type, ...)				\
134 	__fsck_err(c, FSCK_CAN_FIX, _err_type, __VA_ARGS__)
135 
136 #define mustfix_fsck_err_on(cond, c, _err_type, ...)			\
137 	__fsck_err_on(cond, c, FSCK_CAN_FIX, _err_type, __VA_ARGS__)
138 
139 #define fsck_err(c, _err_type, ...)					\
140 	__fsck_err(c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, _err_type, __VA_ARGS__)
141 
142 #define fsck_err_on(cond, c, _err_type, ...)				\
143 	__fsck_err_on(cond, c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, _err_type, __VA_ARGS__)
144 
145 #define log_fsck_err(c, _err_type, ...)					\
146 	__fsck_err(c, FSCK_CAN_IGNORE, _err_type, __VA_ARGS__)
147 
148 #define log_fsck_err_on(cond, ...)					\
149 ({									\
150 	bool _ret = unlikely(!!(cond));					\
151 	if (_ret)							\
152 		log_fsck_err(__VA_ARGS__);				\
153 	_ret;								\
154 })
155 
156 enum bch_validate_flags;
157 __printf(5, 6)
158 int __bch2_bkey_fsck_err(struct bch_fs *,
159 			 struct bkey_s_c,
160 			 struct bkey_validate_context from,
161 			 enum bch_sb_error_id,
162 			 const char *, ...);
163 
164 /*
165  * for now, bkey fsck errors are always handled by deleting the entire key -
166  * this will change at some point
167  */
168 #define bkey_fsck_err(c, _err_type, _err_msg, ...)			\
169 do {									\
170 	int _ret = __bch2_bkey_fsck_err(c, k, from,			\
171 				BCH_FSCK_ERR_##_err_type,		\
172 				_err_msg, ##__VA_ARGS__);		\
173 	if (!bch2_err_matches(_ret, BCH_ERR_fsck_fix) &&		\
174 	    !bch2_err_matches(_ret, BCH_ERR_fsck_ignore))		\
175 		ret = _ret;						\
176 	ret = bch_err_throw(c, fsck_delete_bkey);			\
177 	goto fsck_err;							\
178 } while (0)
179 
180 #define bkey_fsck_err_on(cond, ...)					\
181 do {									\
182 	if (unlikely(cond))						\
183 		bkey_fsck_err(__VA_ARGS__);				\
184 } while (0)
185 
186 /*
187  * Fatal errors: these don't indicate a bug, but we can't continue running in RW
188  * mode - pretty much just due to metadata IO errors:
189  */
190 
191 void bch2_fatal_error(struct bch_fs *);
192 
193 #define bch2_fs_fatal_error(c, _msg, ...)				\
194 do {									\
195 	bch_err(c, "%s(): fatal error " _msg, __func__, ##__VA_ARGS__);	\
196 	bch2_fatal_error(c);						\
197 } while (0)
198 
199 #define bch2_fs_fatal_err_on(cond, c, ...)				\
200 ({									\
201 	bool _ret = unlikely(!!(cond));					\
202 									\
203 	if (_ret)							\
204 		bch2_fs_fatal_error(c, __VA_ARGS__);			\
205 	_ret;								\
206 })
207 
208 /*
209  * IO errors: either recoverable metadata IO (because we have replicas), or data
210  * IO - we need to log it and print out a message, but we don't (necessarily)
211  * want to shut down the fs:
212  */
213 
214 void bch2_io_error_work(struct work_struct *);
215 
216 /* Does the error handling without logging a message */
217 void bch2_io_error(struct bch_dev *, enum bch_member_error_type);
218 
219 #ifndef CONFIG_BCACHEFS_NO_LATENCY_ACCT
220 void bch2_latency_acct(struct bch_dev *, u64, int);
221 #else
bch2_latency_acct(struct bch_dev * ca,u64 submit_time,int rw)222 static inline void bch2_latency_acct(struct bch_dev *ca, u64 submit_time, int rw) {}
223 #endif
224 
bch2_account_io_success_fail(struct bch_dev * ca,enum bch_member_error_type type,bool success)225 static inline void bch2_account_io_success_fail(struct bch_dev *ca,
226 						enum bch_member_error_type type,
227 						bool success)
228 {
229 	if (likely(success)) {
230 		if (type == BCH_MEMBER_ERROR_write &&
231 		    ca->write_errors_start)
232 			ca->write_errors_start = 0;
233 	} else {
234 		bch2_io_error(ca, type);
235 	}
236 }
237 
bch2_account_io_completion(struct bch_dev * ca,enum bch_member_error_type type,u64 submit_time,bool success)238 static inline void bch2_account_io_completion(struct bch_dev *ca,
239 					      enum bch_member_error_type type,
240 					      u64 submit_time, bool success)
241 {
242 	if (unlikely(!ca))
243 		return;
244 
245 	if (type != BCH_MEMBER_ERROR_checksum)
246 		bch2_latency_acct(ca, submit_time, type);
247 
248 	bch2_account_io_success_fail(ca, type, success);
249 }
250 
251 int bch2_inum_offset_err_msg_trans(struct btree_trans *, struct printbuf *, subvol_inum, u64);
252 
253 void bch2_inum_offset_err_msg(struct bch_fs *, struct printbuf *, subvol_inum, u64);
254 
255 int bch2_inum_snap_offset_err_msg_trans(struct btree_trans *, struct printbuf *, struct bpos);
256 void bch2_inum_snap_offset_err_msg(struct bch_fs *, struct printbuf *, struct bpos);
257 
258 #endif /* _BCACHEFS_ERROR_H */
259