1/*
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18#include "xfs.h"
19#include "xfs_format.h"
20#include "xfs_fs.h"
21#include "xfs_log_format.h"
22#include "xfs_trans_resv.h"
23#include "xfs_mount.h"
24#include "xfs_error.h"
25
26#ifdef DEBUG
27
28int	xfs_etest[XFS_NUM_INJECT_ERROR];
29int64_t	xfs_etest_fsid[XFS_NUM_INJECT_ERROR];
30char *	xfs_etest_fsname[XFS_NUM_INJECT_ERROR];
31int	xfs_error_test_active;
32
33int
34xfs_error_test(int error_tag, int *fsidp, char *expression,
35	       int line, char *file, unsigned long randfactor)
36{
37	int i;
38	int64_t fsid;
39
40	if (prandom_u32() % randfactor)
41		return 0;
42
43	memcpy(&fsid, fsidp, sizeof(xfs_fsid_t));
44
45	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
46		if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) {
47			xfs_warn(NULL,
48	"Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
49				expression, file, line, xfs_etest_fsname[i]);
50			return 1;
51		}
52	}
53
54	return 0;
55}
56
57int
58xfs_errortag_add(int error_tag, xfs_mount_t *mp)
59{
60	int i;
61	int len;
62	int64_t fsid;
63
64	memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
65
66	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
67		if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
68			xfs_warn(mp, "error tag #%d on", error_tag);
69			return 0;
70		}
71	}
72
73	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
74		if (xfs_etest[i] == 0) {
75			xfs_warn(mp, "Turned on XFS error tag #%d",
76				error_tag);
77			xfs_etest[i] = error_tag;
78			xfs_etest_fsid[i] = fsid;
79			len = strlen(mp->m_fsname);
80			xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP);
81			strcpy(xfs_etest_fsname[i], mp->m_fsname);
82			xfs_error_test_active++;
83			return 0;
84		}
85	}
86
87	xfs_warn(mp, "error tag overflow, too many turned on");
88
89	return 1;
90}
91
92int
93xfs_errortag_clearall(xfs_mount_t *mp, int loud)
94{
95	int64_t fsid;
96	int cleared = 0;
97	int i;
98
99	memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
100
101
102	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
103		if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) &&
104		     xfs_etest[i] != 0) {
105			cleared = 1;
106			xfs_warn(mp, "Clearing XFS error tag #%d",
107				xfs_etest[i]);
108			xfs_etest[i] = 0;
109			xfs_etest_fsid[i] = 0LL;
110			kmem_free(xfs_etest_fsname[i]);
111			xfs_etest_fsname[i] = NULL;
112			xfs_error_test_active--;
113		}
114	}
115
116	if (loud || cleared)
117		xfs_warn(mp, "Cleared all XFS error tags for filesystem");
118
119	return 0;
120}
121#endif /* DEBUG */
122
123void
124xfs_error_report(
125	const char		*tag,
126	int			level,
127	struct xfs_mount	*mp,
128	const char		*filename,
129	int			linenum,
130	inst_t			*ra)
131{
132	if (level <= xfs_error_level) {
133		xfs_alert_tag(mp, XFS_PTAG_ERROR_REPORT,
134		"Internal error %s at line %d of file %s.  Caller %pS",
135			    tag, linenum, filename, ra);
136
137		xfs_stack_trace();
138	}
139}
140
141void
142xfs_corruption_error(
143	const char		*tag,
144	int			level,
145	struct xfs_mount	*mp,
146	void			*p,
147	const char		*filename,
148	int			linenum,
149	inst_t			*ra)
150{
151	if (level <= xfs_error_level)
152		xfs_hex_dump(p, 64);
153	xfs_error_report(tag, level, mp, filename, linenum, ra);
154	xfs_alert(mp, "Corruption detected. Unmount and run xfs_repair");
155}
156
157/*
158 * Warnings specifically for verifier errors.  Differentiate CRC vs. invalid
159 * values, and omit the stack trace unless the error level is tuned high.
160 */
161void
162xfs_verifier_error(
163	struct xfs_buf		*bp)
164{
165	struct xfs_mount *mp = bp->b_target->bt_mount;
166
167	xfs_alert(mp, "Metadata %s detected at %pF, block 0x%llx",
168		  bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",
169		  __return_address, bp->b_bn);
170
171	xfs_alert(mp, "Unmount and run xfs_repair");
172
173	if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
174		xfs_alert(mp, "First 64 bytes of corrupted metadata buffer:");
175		xfs_hex_dump(xfs_buf_offset(bp, 0), 64);
176	}
177
178	if (xfs_error_level >= XFS_ERRLEVEL_HIGH)
179		xfs_stack_trace();
180}
181