1153323Srodrigc/*
2159451Srodrigc * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3159451Srodrigc * All Rights Reserved.
4153323Srodrigc *
5159451Srodrigc * This program is free software; you can redistribute it and/or
6159451Srodrigc * modify it under the terms of the GNU General Public License as
7153323Srodrigc * published by the Free Software Foundation.
8153323Srodrigc *
9159451Srodrigc * This program is distributed in the hope that it would be useful,
10159451Srodrigc * but WITHOUT ANY WARRANTY; without even the implied warranty of
11159451Srodrigc * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12159451Srodrigc * GNU General Public License for more details.
13153323Srodrigc *
14159451Srodrigc * You should have received a copy of the GNU General Public License
15159451Srodrigc * along with this program; if not, write the Free Software Foundation,
16159451Srodrigc * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17153323Srodrigc */
18153323Srodrigc#include "xfs.h"
19159451Srodrigc#include "xfs_fs.h"
20153323Srodrigc#include "xfs_types.h"
21159451Srodrigc#include "xfs_log.h"
22153323Srodrigc#include "xfs_inum.h"
23159451Srodrigc#include "xfs_trans.h"
24153323Srodrigc#include "xfs_sb.h"
25153323Srodrigc#include "xfs_dir.h"
26153323Srodrigc#include "xfs_dir2.h"
27153323Srodrigc#include "xfs_dmapi.h"
28153323Srodrigc#include "xfs_mount.h"
29153323Srodrigc#include "xfs_bmap_btree.h"
30153323Srodrigc#include "xfs_dir_sf.h"
31153323Srodrigc#include "xfs_dir2_sf.h"
32159451Srodrigc#include "xfs_attr_sf.h"
33153323Srodrigc#include "xfs_dinode.h"
34153323Srodrigc#include "xfs_inode.h"
35153323Srodrigc#include "xfs_utils.h"
36153323Srodrigc#include "xfs_error.h"
37153323Srodrigc
38153323Srodrigc#ifdef DEBUG
39153323Srodrigc
40153323Srodrigcint	xfs_etrap[XFS_ERROR_NTRAP] = {
41153323Srodrigc	0,
42153323Srodrigc};
43153323Srodrigc
44153323Srodrigcint
45153323Srodrigcxfs_error_trap(int e)
46153323Srodrigc{
47153323Srodrigc	int i;
48153323Srodrigc
49153323Srodrigc	if (!e)
50153323Srodrigc		return 0;
51153323Srodrigc	for (i = 0; i < XFS_ERROR_NTRAP; i++) {
52153323Srodrigc		if (xfs_etrap[i] == 0)
53153323Srodrigc			break;
54153323Srodrigc		if (e != xfs_etrap[i])
55153323Srodrigc			continue;
56153323Srodrigc		cmn_err(CE_NOTE, "xfs_error_trap: error %d", e);
57153323Srodrigc		panic("xfs_error_trap");
58153323Srodrigc		break;
59153323Srodrigc	}
60153323Srodrigc	return e;
61153323Srodrigc}
62153323Srodrigc#endif
63153323Srodrigc
64153323Srodrigc#if (defined(DEBUG) || defined(INDUCE_IO_ERROR))
65153323Srodrigc
66153323Srodrigcint	xfs_etest[XFS_NUM_INJECT_ERROR];
67153323Srodrigcint64_t	xfs_etest_fsid[XFS_NUM_INJECT_ERROR];
68153323Srodrigcchar *	xfs_etest_fsname[XFS_NUM_INJECT_ERROR];
69153323Srodrigc
70153323Srodrigcvoid
71153323Srodrigcxfs_error_test_init(void)
72153323Srodrigc{
73153323Srodrigc	memset(xfs_etest, 0, sizeof(xfs_etest));
74153323Srodrigc	memset(xfs_etest_fsid, 0, sizeof(xfs_etest_fsid));
75153323Srodrigc	memset(xfs_etest_fsname, 0, sizeof(xfs_etest_fsname));
76153323Srodrigc}
77153323Srodrigc
78153323Srodrigcint
79153323Srodrigcxfs_error_test(int error_tag, int *fsidp, char *expression,
80153323Srodrigc	       int line, char *file, unsigned long randfactor)
81153323Srodrigc{
82153323Srodrigc	int i;
83153323Srodrigc	int64_t fsid;
84153323Srodrigc
85153323Srodrigc	if (random() % randfactor)
86153323Srodrigc		return 0;
87153323Srodrigc
88153323Srodrigc	memcpy(&fsid, fsidp, sizeof(xfs_fsid_t));
89153323Srodrigc
90153323Srodrigc	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
91153323Srodrigc		if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) {
92153323Srodrigc			cmn_err(CE_WARN,
93153323Srodrigc	"Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
94153323Srodrigc				expression, file, line, xfs_etest_fsname[i]);
95153323Srodrigc			return 1;
96153323Srodrigc		}
97153323Srodrigc	}
98153323Srodrigc
99153323Srodrigc	return 0;
100153323Srodrigc}
101153323Srodrigc
102153323Srodrigcint
103153323Srodrigcxfs_errortag_add(int error_tag, xfs_mount_t *mp)
104153323Srodrigc{
105153323Srodrigc	int i;
106153323Srodrigc	int len;
107153323Srodrigc	int64_t fsid;
108153323Srodrigc
109153323Srodrigc	memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
110153323Srodrigc
111153323Srodrigc	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
112153323Srodrigc		if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
113153323Srodrigc			cmn_err(CE_WARN, "XFS error tag #%d on", error_tag);
114153323Srodrigc			return 0;
115153323Srodrigc		}
116153323Srodrigc	}
117153323Srodrigc
118153323Srodrigc	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
119153323Srodrigc		if (xfs_etest[i] == 0) {
120153323Srodrigc			cmn_err(CE_WARN, "Turned on XFS error tag #%d",
121153323Srodrigc				error_tag);
122153323Srodrigc			xfs_etest[i] = error_tag;
123153323Srodrigc			xfs_etest_fsid[i] = fsid;
124153323Srodrigc			len = strlen(mp->m_fsname);
125153323Srodrigc			xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP);
126153323Srodrigc			strcpy(xfs_etest_fsname[i], mp->m_fsname);
127153323Srodrigc			return 0;
128153323Srodrigc		}
129153323Srodrigc	}
130153323Srodrigc
131153323Srodrigc	cmn_err(CE_WARN, "error tag overflow, too many turned on");
132153323Srodrigc
133153323Srodrigc	return 1;
134153323Srodrigc}
135153323Srodrigc
136153323Srodrigcint
137153323Srodrigcxfs_errortag_clear(int error_tag, xfs_mount_t *mp)
138153323Srodrigc{
139153323Srodrigc	int i;
140153323Srodrigc	int64_t fsid;
141153323Srodrigc
142153323Srodrigc	memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
143153323Srodrigc
144153323Srodrigc	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
145153323Srodrigc		if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
146153323Srodrigc			xfs_etest[i] = 0;
147153323Srodrigc			xfs_etest_fsid[i] = 0LL;
148153323Srodrigc			kmem_free(xfs_etest_fsname[i],
149153323Srodrigc				  strlen(xfs_etest_fsname[i]) + 1);
150153323Srodrigc			xfs_etest_fsname[i] = NULL;
151153323Srodrigc			cmn_err(CE_WARN, "Cleared XFS error tag #%d",
152153323Srodrigc				error_tag);
153153323Srodrigc			return 0;
154153323Srodrigc		}
155153323Srodrigc	}
156153323Srodrigc
157153323Srodrigc	cmn_err(CE_WARN, "XFS error tag %d not on", error_tag);
158153323Srodrigc
159153323Srodrigc	return 1;
160153323Srodrigc}
161153323Srodrigc
162153323Srodrigcint
163153323Srodrigcxfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud)
164153323Srodrigc{
165153323Srodrigc	int i;
166153323Srodrigc	int cleared = 0;
167153323Srodrigc
168153323Srodrigc	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
169153323Srodrigc		if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) &&
170153323Srodrigc		     xfs_etest[i] != 0) {
171153323Srodrigc			cleared = 1;
172153323Srodrigc			cmn_err(CE_WARN, "Clearing XFS error tag #%d",
173153323Srodrigc				xfs_etest[i]);
174153323Srodrigc			xfs_etest[i] = 0;
175153323Srodrigc			xfs_etest_fsid[i] = 0LL;
176153323Srodrigc			kmem_free(xfs_etest_fsname[i],
177153323Srodrigc				  strlen(xfs_etest_fsname[i]) + 1);
178153323Srodrigc			xfs_etest_fsname[i] = NULL;
179153323Srodrigc		}
180153323Srodrigc	}
181153323Srodrigc
182153323Srodrigc	if (loud || cleared)
183153323Srodrigc		cmn_err(CE_WARN,
184153323Srodrigc			"Cleared all XFS error tags for filesystem \"%s\"",
185153323Srodrigc			fsname);
186153323Srodrigc
187153323Srodrigc	return 0;
188153323Srodrigc}
189153323Srodrigc
190153323Srodrigcint
191153323Srodrigcxfs_errortag_clearall(xfs_mount_t *mp)
192153323Srodrigc{
193153323Srodrigc	int64_t fsid;
194153323Srodrigc
195153323Srodrigc	memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
196153323Srodrigc
197153323Srodrigc	return xfs_errortag_clearall_umount(fsid, mp->m_fsname, 1);
198153323Srodrigc}
199153323Srodrigc#endif /* DEBUG || INDUCE_IO_ERROR */
200153323Srodrigc
201153323Srodrigcstatic void
202153323Srodrigcxfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap)
203153323Srodrigc{
204153323Srodrigc	if (mp != NULL) {
205153323Srodrigc		char	*newfmt;
206153323Srodrigc		int	len = 16 + mp->m_fsname_len + strlen(fmt);
207153323Srodrigc
208153323Srodrigc		newfmt = kmem_alloc(len, KM_SLEEP);
209153323Srodrigc		sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt);
210153323Srodrigc		icmn_err(level, newfmt, ap);
211153323Srodrigc		kmem_free(newfmt, len);
212153323Srodrigc	} else {
213153323Srodrigc		icmn_err(level, fmt, ap);
214153323Srodrigc	}
215153323Srodrigc}
216153323Srodrigc
217153323Srodrigcvoid
218153323Srodrigcxfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
219153323Srodrigc{
220153323Srodrigc	va_list ap;
221153323Srodrigc
222153323Srodrigc	va_start(ap, fmt);
223153323Srodrigc	xfs_fs_vcmn_err(level, mp, fmt, ap);
224153323Srodrigc	va_end(ap);
225153323Srodrigc}
226153323Srodrigc
227153323Srodrigcvoid
228153323Srodrigcxfs_cmn_err(int panic_tag, int level, xfs_mount_t *mp, char *fmt, ...)
229153323Srodrigc{
230153323Srodrigc	va_list ap;
231153323Srodrigc
232153323Srodrigc#ifdef DEBUG
233153323Srodrigc	xfs_panic_mask |= XFS_PTAG_SHUTDOWN_CORRUPT;
234153323Srodrigc#endif
235153323Srodrigc
236153323Srodrigc	if (xfs_panic_mask && (xfs_panic_mask & panic_tag)
237153323Srodrigc	    && (level & CE_ALERT)) {
238153323Srodrigc		level &= ~CE_ALERT;
239153323Srodrigc		level |= CE_PANIC;
240153323Srodrigc		cmn_err(CE_ALERT, "XFS: Transforming an alert into a BUG.");
241153323Srodrigc	}
242153323Srodrigc	va_start(ap, fmt);
243153323Srodrigc	xfs_fs_vcmn_err(level, mp, fmt, ap);
244153323Srodrigc	va_end(ap);
245153323Srodrigc}
246153323Srodrigc
247153323Srodrigcvoid
248153323Srodrigcxfs_error_report(
249153323Srodrigc	char		*tag,
250153323Srodrigc	int		level,
251153323Srodrigc	xfs_mount_t	*mp,
252153323Srodrigc	char		*fname,
253153323Srodrigc	int		linenum,
254153323Srodrigc	inst_t		*ra)
255153323Srodrigc{
256153323Srodrigc	if (level <= xfs_error_level) {
257153323Srodrigc		xfs_cmn_err(XFS_PTAG_ERROR_REPORT,
258153323Srodrigc			    CE_ALERT, mp,
259153323Srodrigc		"XFS internal error %s at line %d of file %s.  Caller 0x%p\n",
260153323Srodrigc			    tag, linenum, fname, ra);
261153323Srodrigc
262153323Srodrigc		xfs_stack_trace();
263153323Srodrigc	}
264153323Srodrigc}
265153323Srodrigc
266159451SrodrigcSTATIC void
267153323Srodrigcxfs_hex_dump(void *p, int length)
268153323Srodrigc{
269153323Srodrigc	__uint8_t *uip = (__uint8_t*)p;
270153323Srodrigc	int	i;
271153323Srodrigc	char	sbuf[128], *s;
272153323Srodrigc
273153323Srodrigc	s = sbuf;
274153323Srodrigc	*s = '\0';
275153323Srodrigc	for (i=0; i<length; i++, uip++) {
276153323Srodrigc		if ((i % 16) == 0) {
277153323Srodrigc			if (*s != '\0')
278153323Srodrigc				cmn_err(CE_ALERT, "%s\n", sbuf);
279153323Srodrigc			s = sbuf;
280153323Srodrigc			sprintf(s, "0x%x: ", i);
281153323Srodrigc			while( *s != '\0')
282153323Srodrigc				s++;
283153323Srodrigc		}
284153323Srodrigc		sprintf(s, "%02x ", *uip);
285153323Srodrigc
286153323Srodrigc		/*
287153323Srodrigc		 * the kernel sprintf is a void; user sprintf returns
288153323Srodrigc		 * the sprintf'ed string's length.  Find the new end-
289153323Srodrigc		 * of-string
290153323Srodrigc		 */
291153323Srodrigc		while( *s != '\0')
292153323Srodrigc			s++;
293153323Srodrigc	}
294153323Srodrigc	cmn_err(CE_ALERT, "%s\n", sbuf);
295153323Srodrigc}
296153323Srodrigc
297153323Srodrigcvoid
298153323Srodrigcxfs_corruption_error(
299153323Srodrigc	char		*tag,
300153323Srodrigc	int		level,
301153323Srodrigc	xfs_mount_t	*mp,
302153323Srodrigc	void		*p,
303153323Srodrigc	char		*fname,
304153323Srodrigc	int		linenum,
305153323Srodrigc	inst_t		*ra)
306153323Srodrigc{
307153323Srodrigc	if (level <= xfs_error_level)
308153323Srodrigc		xfs_hex_dump(p, 16);
309153323Srodrigc	xfs_error_report(tag, level, mp, fname, linenum, ra);
310153323Srodrigc}
311153323Srodrigc
312