Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / fs / xfs / xfs_error.c
1 /*
2  * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32
33 #include "xfs.h"
34
35 #include "xfs_macros.h"
36 #include "xfs_types.h"
37 #include "xfs_inum.h"
38 #include "xfs_log.h"
39 #include "xfs_sb.h"
40 #include "xfs_trans.h"
41 #include "xfs_dir.h"
42 #include "xfs_dir2.h"
43 #include "xfs_dmapi.h"
44 #include "xfs_mount.h"
45 #include "xfs_bmap_btree.h"
46 #include "xfs_attr_sf.h"
47 #include "xfs_dir_sf.h"
48 #include "xfs_dir2_sf.h"
49 #include "xfs_dinode.h"
50 #include "xfs_inode.h"
51 #include "xfs_utils.h"
52 #include "xfs_error.h"
53
54 #ifdef DEBUG
55
56 int     xfs_etrap[XFS_ERROR_NTRAP] = {
57         0,
58 };
59
60 int
61 xfs_error_trap(int e)
62 {
63         int i;
64
65         if (!e)
66                 return 0;
67         for (i = 0; i < XFS_ERROR_NTRAP; i++) {
68                 if (xfs_etrap[i] == 0)
69                         break;
70                 if (e != xfs_etrap[i])
71                         continue;
72                 cmn_err(CE_NOTE, "xfs_error_trap: error %d", e);
73                 debug_stop_all_cpus((void *)-1LL);
74                 BUG();
75                 break;
76         }
77         return e;
78 }
79 #endif
80
81 #if (defined(DEBUG) || defined(INDUCE_IO_ERROR))
82
83 int     xfs_etest[XFS_NUM_INJECT_ERROR];
84 int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR];
85 char *  xfs_etest_fsname[XFS_NUM_INJECT_ERROR];
86
87 void
88 xfs_error_test_init(void)
89 {
90         memset(xfs_etest, 0, sizeof(xfs_etest));
91         memset(xfs_etest_fsid, 0, sizeof(xfs_etest_fsid));
92         memset(xfs_etest_fsname, 0, sizeof(xfs_etest_fsname));
93 }
94
95 int
96 xfs_error_test(int error_tag, int *fsidp, char *expression,
97                int line, char *file, unsigned long randfactor)
98 {
99         int i;
100         int64_t fsid;
101
102         if (random() % randfactor)
103                 return 0;
104
105         memcpy(&fsid, fsidp, sizeof(xfs_fsid_t));
106
107         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
108                 if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) {
109                         cmn_err(CE_WARN,
110         "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
111                                 expression, file, line, xfs_etest_fsname[i]);
112                         return 1;
113                 }
114         }
115
116         return 0;
117 }
118
119 int
120 xfs_errortag_add(int error_tag, xfs_mount_t *mp)
121 {
122         int i;
123         int len;
124         int64_t fsid;
125
126         memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
127
128         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
129                 if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
130                         cmn_err(CE_WARN, "XFS error tag #%d on", error_tag);
131                         return 0;
132                 }
133         }
134
135         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
136                 if (xfs_etest[i] == 0) {
137                         cmn_err(CE_WARN, "Turned on XFS error tag #%d",
138                                 error_tag);
139                         xfs_etest[i] = error_tag;
140                         xfs_etest_fsid[i] = fsid;
141                         len = strlen(mp->m_fsname);
142                         xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP);
143                         strcpy(xfs_etest_fsname[i], mp->m_fsname);
144                         return 0;
145                 }
146         }
147
148         cmn_err(CE_WARN, "error tag overflow, too many turned on");
149
150         return 1;
151 }
152
153 int
154 xfs_errortag_clear(int error_tag, xfs_mount_t *mp)
155 {
156         int i;
157         int64_t fsid;
158
159         memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
160
161         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
162                 if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
163                         xfs_etest[i] = 0;
164                         xfs_etest_fsid[i] = 0LL;
165                         kmem_free(xfs_etest_fsname[i],
166                                   strlen(xfs_etest_fsname[i]) + 1);
167                         xfs_etest_fsname[i] = NULL;
168                         cmn_err(CE_WARN, "Cleared XFS error tag #%d",
169                                 error_tag);
170                         return 0;
171                 }
172         }
173
174         cmn_err(CE_WARN, "XFS error tag %d not on", error_tag);
175
176         return 1;
177 }
178
179 int
180 xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud)
181 {
182         int i;
183         int cleared = 0;
184
185         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
186                 if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) &&
187                      xfs_etest[i] != 0) {
188                         cleared = 1;
189                         cmn_err(CE_WARN, "Clearing XFS error tag #%d",
190                                 xfs_etest[i]);
191                         xfs_etest[i] = 0;
192                         xfs_etest_fsid[i] = 0LL;
193                         kmem_free(xfs_etest_fsname[i],
194                                   strlen(xfs_etest_fsname[i]) + 1);
195                         xfs_etest_fsname[i] = NULL;
196                 }
197         }
198
199         if (loud || cleared)
200                 cmn_err(CE_WARN,
201                         "Cleared all XFS error tags for filesystem \"%s\"",
202                         fsname);
203
204         return 0;
205 }
206
207 int
208 xfs_errortag_clearall(xfs_mount_t *mp)
209 {
210         int64_t fsid;
211
212         memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
213
214         return xfs_errortag_clearall_umount(fsid, mp->m_fsname, 1);
215 }
216 #endif /* DEBUG || INDUCE_IO_ERROR */
217
218 static void
219 xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap)
220 {
221         if (mp != NULL) {
222                 char    *newfmt;
223                 int     len = 16 + mp->m_fsname_len + strlen(fmt);
224
225                 newfmt = kmem_alloc(len, KM_SLEEP);
226                 sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt);
227                 icmn_err(level, newfmt, ap);
228                 kmem_free(newfmt, len);
229         } else {
230                 icmn_err(level, fmt, ap);
231         }
232 }
233
234 void
235 xfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
236 {
237         va_list ap;
238
239         va_start(ap, fmt);
240         xfs_fs_vcmn_err(level, mp, fmt, ap);
241         va_end(ap);
242 }
243
244 void
245 xfs_cmn_err(int panic_tag, int level, xfs_mount_t *mp, char *fmt, ...)
246 {
247         va_list ap;
248
249 #ifdef DEBUG
250         xfs_panic_mask |= XFS_PTAG_SHUTDOWN_CORRUPT;
251 #endif
252
253         if (xfs_panic_mask && (xfs_panic_mask & panic_tag)
254             && (level & CE_ALERT)) {
255                 level &= ~CE_ALERT;
256                 level |= CE_PANIC;
257                 cmn_err(CE_ALERT, "XFS: Transforming an alert into a BUG.");
258         }
259         va_start(ap, fmt);
260         xfs_fs_vcmn_err(level, mp, fmt, ap);
261         va_end(ap);
262 }
263
264 void
265 xfs_error_report(
266         char            *tag,
267         int             level,
268         xfs_mount_t     *mp,
269         char            *fname,
270         int             linenum,
271         inst_t          *ra)
272 {
273         if (level <= xfs_error_level) {
274                 xfs_cmn_err(XFS_PTAG_ERROR_REPORT,
275                             CE_ALERT, mp,
276                 "XFS internal error %s at line %d of file %s.  Caller 0x%p\n",
277                             tag, linenum, fname, ra);
278
279                 xfs_stack_trace();
280         }
281 }
282
283 STATIC void
284 xfs_hex_dump(void *p, int length)
285 {
286         __uint8_t *uip = (__uint8_t*)p;
287         int     i;
288         char    sbuf[128], *s;
289
290         s = sbuf;
291         *s = '\0';
292         for (i=0; i<length; i++, uip++) {
293                 if ((i % 16) == 0) {
294                         if (*s != '\0')
295                                 cmn_err(CE_ALERT, "%s\n", sbuf);
296                         s = sbuf;
297                         sprintf(s, "0x%x: ", i);
298                         while( *s != '\0')
299                                 s++;
300                 }
301                 sprintf(s, "%02x ", *uip);
302
303                 /*
304                  * the kernel sprintf is a void; user sprintf returns
305                  * the sprintf'ed string's length.  Find the new end-
306                  * of-string
307                  */
308                 while( *s != '\0')
309                         s++;
310         }
311         cmn_err(CE_ALERT, "%s\n", sbuf);
312 }
313
314 void
315 xfs_corruption_error(
316         char            *tag,
317         int             level,
318         xfs_mount_t     *mp,
319         void            *p,
320         char            *fname,
321         int             linenum,
322         inst_t          *ra)
323 {
324         if (level <= xfs_error_level)
325                 xfs_hex_dump(p, 16);
326         xfs_error_report(tag, level, mp, fname, linenum, ra);
327 }