Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6#include "xfs.h"
7#include "xfs_shared.h"
8#include "xfs_format.h"
9#include "xfs_fs.h"
10#include "xfs_log_format.h"
11#include "xfs_trans_resv.h"
12#include "xfs_mount.h"
13#include "xfs_error.h"
14#include "xfs_sysfs.h"
15#include "xfs_inode.h"
16
17#ifdef DEBUG
18
19#define XFS_ERRTAG(_tag, _name, _default) \
20 [XFS_ERRTAG_##_tag] = (_default),
21#include "xfs_errortag.h"
22static const unsigned int xfs_errortag_random_default[] = { XFS_ERRTAGS };
23#undef XFS_ERRTAG
24
25struct xfs_errortag_attr {
26 struct attribute attr;
27 unsigned int tag;
28};
29
30static inline struct xfs_errortag_attr *
31to_attr(struct attribute *attr)
32{
33 return container_of(attr, struct xfs_errortag_attr, attr);
34}
35
36static inline struct xfs_mount *
37to_mp(struct kobject *kobject)
38{
39 struct xfs_kobj *kobj = to_kobj(kobject);
40
41 return container_of(kobj, struct xfs_mount, m_errortag_kobj);
42}
43
44STATIC ssize_t
45xfs_errortag_attr_store(
46 struct kobject *kobject,
47 struct attribute *attr,
48 const char *buf,
49 size_t count)
50{
51 struct xfs_mount *mp = to_mp(kobject);
52 unsigned int error_tag = to_attr(attr)->tag;
53 int ret;
54
55 if (strcmp(buf, "default") == 0) {
56 mp->m_errortag[error_tag] =
57 xfs_errortag_random_default[error_tag];
58 } else {
59 ret = kstrtouint(buf, 0, &mp->m_errortag[error_tag]);
60 if (ret)
61 return ret;
62 }
63
64 return count;
65}
66
67STATIC ssize_t
68xfs_errortag_attr_show(
69 struct kobject *kobject,
70 struct attribute *attr,
71 char *buf)
72{
73 struct xfs_mount *mp = to_mp(kobject);
74 unsigned int error_tag = to_attr(attr)->tag;
75
76 return snprintf(buf, PAGE_SIZE, "%u\n", mp->m_errortag[error_tag]);
77}
78
79static const struct sysfs_ops xfs_errortag_sysfs_ops = {
80 .show = xfs_errortag_attr_show,
81 .store = xfs_errortag_attr_store,
82};
83
84#define XFS_ERRTAG(_tag, _name, _default) \
85static struct xfs_errortag_attr xfs_errortag_attr_##_name = { \
86 .attr = {.name = __stringify(_name), \
87 .mode = VERIFY_OCTAL_PERMISSIONS(S_IWUSR | S_IRUGO) }, \
88 .tag = XFS_ERRTAG_##_tag, \
89};
90#include "xfs_errortag.h"
91XFS_ERRTAGS
92#undef XFS_ERRTAG
93
94#define XFS_ERRTAG(_tag, _name, _default) \
95 &xfs_errortag_attr_##_name.attr,
96#include "xfs_errortag.h"
97static struct attribute *xfs_errortag_attrs[] = {
98 XFS_ERRTAGS
99 NULL
100};
101ATTRIBUTE_GROUPS(xfs_errortag);
102#undef XFS_ERRTAG
103
104/* -1 because XFS_ERRTAG_DROP_WRITES got removed, + 1 for NULL termination */
105static_assert(ARRAY_SIZE(xfs_errortag_attrs) == XFS_ERRTAG_MAX);
106
107static const struct kobj_type xfs_errortag_ktype = {
108 .release = xfs_sysfs_release,
109 .sysfs_ops = &xfs_errortag_sysfs_ops,
110 .default_groups = xfs_errortag_groups,
111};
112
113int
114xfs_errortag_init(
115 struct xfs_mount *mp)
116{
117 int ret;
118
119 mp->m_errortag = kzalloc(sizeof(unsigned int) * XFS_ERRTAG_MAX,
120 GFP_KERNEL | __GFP_RETRY_MAYFAIL);
121 if (!mp->m_errortag)
122 return -ENOMEM;
123
124 ret = xfs_sysfs_init(&mp->m_errortag_kobj, &xfs_errortag_ktype,
125 &mp->m_kobj, "errortag");
126 if (ret)
127 kfree(mp->m_errortag);
128 return ret;
129}
130
131void
132xfs_errortag_del(
133 struct xfs_mount *mp)
134{
135 xfs_sysfs_del(&mp->m_errortag_kobj);
136 kfree(mp->m_errortag);
137}
138
139static bool
140xfs_errortag_valid(
141 unsigned int error_tag)
142{
143 if (error_tag >= XFS_ERRTAG_MAX)
144 return false;
145
146 /* Error out removed injection types */
147 if (error_tag == XFS_ERRTAG_DROP_WRITES)
148 return false;
149 return true;
150}
151
152bool
153xfs_errortag_enabled(
154 struct xfs_mount *mp,
155 unsigned int tag)
156{
157 if (!mp->m_errortag)
158 return false;
159 if (!xfs_errortag_valid(tag))
160 return false;
161
162 return mp->m_errortag[tag] != 0;
163}
164
165bool
166xfs_errortag_test(
167 struct xfs_mount *mp,
168 const char *file,
169 int line,
170 unsigned int error_tag)
171{
172 unsigned int randfactor;
173
174 /*
175 * To be able to use error injection anywhere, we need to ensure error
176 * injection mechanism is already initialized.
177 *
178 * Code paths like I/O completion can be called before the
179 * initialization is complete, but be able to inject errors in such
180 * places is still useful.
181 */
182 if (!mp->m_errortag)
183 return false;
184
185 if (!xfs_errortag_valid(error_tag))
186 return false;
187
188 randfactor = mp->m_errortag[error_tag];
189 if (!randfactor || get_random_u32_below(randfactor))
190 return false;
191
192 xfs_warn_ratelimited(mp,
193"Injecting error at file %s, line %d, on filesystem \"%s\"",
194 file, line, mp->m_super->s_id);
195 return true;
196}
197
198int
199xfs_errortag_add(
200 struct xfs_mount *mp,
201 unsigned int error_tag)
202{
203 BUILD_BUG_ON(ARRAY_SIZE(xfs_errortag_random_default) != XFS_ERRTAG_MAX);
204
205 if (!xfs_errortag_valid(error_tag))
206 return -EINVAL;
207 mp->m_errortag[error_tag] = xfs_errortag_random_default[error_tag];
208 return 0;
209}
210
211int
212xfs_errortag_clearall(
213 struct xfs_mount *mp)
214{
215 memset(mp->m_errortag, 0, sizeof(unsigned int) * XFS_ERRTAG_MAX);
216 return 0;
217}
218#endif /* DEBUG */
219
220void
221xfs_error_report(
222 const char *tag,
223 int level,
224 struct xfs_mount *mp,
225 const char *filename,
226 int linenum,
227 xfs_failaddr_t failaddr)
228{
229 if (level <= xfs_error_level) {
230 xfs_alert_tag(mp, XFS_PTAG_ERROR_REPORT,
231 "Internal error %s at line %d of file %s. Caller %pS",
232 tag, linenum, filename, failaddr);
233
234 xfs_stack_trace();
235 }
236}
237
238void
239xfs_corruption_error(
240 const char *tag,
241 int level,
242 struct xfs_mount *mp,
243 const void *buf,
244 size_t bufsize,
245 const char *filename,
246 int linenum,
247 xfs_failaddr_t failaddr)
248{
249 if (buf && level <= xfs_error_level)
250 xfs_hex_dump(buf, bufsize);
251 xfs_error_report(tag, level, mp, filename, linenum, failaddr);
252 xfs_alert(mp, "Corruption detected. Unmount and run xfs_repair");
253}
254
255/*
256 * Complain about the kinds of metadata corruption that we can't detect from a
257 * verifier, such as incorrect inter-block relationship data. Does not set
258 * bp->b_error.
259 *
260 * Call xfs_buf_mark_corrupt, not this function.
261 */
262void
263xfs_buf_corruption_error(
264 struct xfs_buf *bp,
265 xfs_failaddr_t fa)
266{
267 struct xfs_mount *mp = bp->b_mount;
268
269 xfs_alert_tag(mp, XFS_PTAG_VERIFIER_ERROR,
270 "Metadata corruption detected at %pS, %s block 0x%llx",
271 fa, bp->b_ops->name, xfs_buf_daddr(bp));
272
273 xfs_alert(mp, "Unmount and run xfs_repair");
274
275 if (xfs_error_level >= XFS_ERRLEVEL_HIGH)
276 xfs_stack_trace();
277}
278
279/*
280 * Warnings specifically for verifier errors. Differentiate CRC vs. invalid
281 * values, and omit the stack trace unless the error level is tuned high.
282 */
283void
284xfs_buf_verifier_error(
285 struct xfs_buf *bp,
286 int error,
287 const char *name,
288 const void *buf,
289 size_t bufsz,
290 xfs_failaddr_t failaddr)
291{
292 struct xfs_mount *mp = bp->b_mount;
293 xfs_failaddr_t fa;
294 int sz;
295
296 fa = failaddr ? failaddr : __return_address;
297 __xfs_buf_ioerror(bp, error, fa);
298
299 xfs_alert_tag(mp, XFS_PTAG_VERIFIER_ERROR,
300 "Metadata %s detected at %pS, %s block 0x%llx %s",
301 bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",
302 fa, bp->b_ops->name, xfs_buf_daddr(bp), name);
303
304 xfs_alert(mp, "Unmount and run xfs_repair");
305
306 if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
307 sz = min_t(size_t, XFS_CORRUPTION_DUMP_LEN, bufsz);
308 xfs_alert(mp, "First %d bytes of corrupted metadata buffer:",
309 sz);
310 xfs_hex_dump(buf, sz);
311 }
312
313 if (xfs_error_level >= XFS_ERRLEVEL_HIGH)
314 xfs_stack_trace();
315}
316
317/*
318 * Warnings specifically for verifier errors. Differentiate CRC vs. invalid
319 * values, and omit the stack trace unless the error level is tuned high.
320 */
321void
322xfs_verifier_error(
323 struct xfs_buf *bp,
324 int error,
325 xfs_failaddr_t failaddr)
326{
327 return xfs_buf_verifier_error(bp, error, "", xfs_buf_offset(bp, 0),
328 XFS_CORRUPTION_DUMP_LEN, failaddr);
329}
330
331/*
332 * Warnings for inode corruption problems. Don't bother with the stack
333 * trace unless the error level is turned up high.
334 */
335void
336xfs_inode_verifier_error(
337 struct xfs_inode *ip,
338 int error,
339 const char *name,
340 const void *buf,
341 size_t bufsz,
342 xfs_failaddr_t failaddr)
343{
344 struct xfs_mount *mp = ip->i_mount;
345 xfs_failaddr_t fa;
346 int sz;
347
348 fa = failaddr ? failaddr : __return_address;
349
350 xfs_alert(mp, "Metadata %s detected at %pS, inode 0x%llx %s",
351 error == -EFSBADCRC ? "CRC error" : "corruption",
352 fa, ip->i_ino, name);
353
354 xfs_alert(mp, "Unmount and run xfs_repair");
355
356 if (buf && xfs_error_level >= XFS_ERRLEVEL_LOW) {
357 sz = min_t(size_t, XFS_CORRUPTION_DUMP_LEN, bufsz);
358 xfs_alert(mp, "First %d bytes of corrupted metadata buffer:",
359 sz);
360 xfs_hex_dump(buf, sz);
361 }
362
363 if (xfs_error_level >= XFS_ERRLEVEL_HIGH)
364 xfs_stack_trace();
365}