Merge branch 'master'
[linux-drm-fsl-dcu.git] / fs / xfs / xfs_error.c
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_fs.h"
20 #include "xfs_types.h"
21 #include "xfs_log.h"
22 #include "xfs_inum.h"
23 #include "xfs_trans.h"
24 #include "xfs_sb.h"
25 #include "xfs_dir.h"
26 #include "xfs_dir2.h"
27 #include "xfs_dmapi.h"
28 #include "xfs_mount.h"
29 #include "xfs_bmap_btree.h"
30 #include "xfs_dir_sf.h"
31 #include "xfs_dir2_sf.h"
32 #include "xfs_attr_sf.h"
33 #include "xfs_dinode.h"
34 #include "xfs_inode.h"
35 #include "xfs_utils.h"
36 #include "xfs_error.h"
37
38 #ifdef DEBUG
39
40 int     xfs_etrap[XFS_ERROR_NTRAP] = {
41         0,
42 };
43
44 int
45 xfs_error_trap(int e)
46 {
47         int i;
48
49         if (!e)
50                 return 0;
51         for (i = 0; i < XFS_ERROR_NTRAP; i++) {
52                 if (xfs_etrap[i] == 0)
53                         break;
54                 if (e != xfs_etrap[i])
55                         continue;
56                 cmn_err(CE_NOTE, "xfs_error_trap: error %d", e);
57                 debug_stop_all_cpus((void *)-1LL);
58                 BUG();
59                 break;
60         }
61         return e;
62 }
63 #endif
64
65 #if (defined(DEBUG) || defined(INDUCE_IO_ERROR))
66
67 int     xfs_etest[XFS_NUM_INJECT_ERROR];
68 int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR];
69 char *  xfs_etest_fsname[XFS_NUM_INJECT_ERROR];
70
71 void
72 xfs_error_test_init(void)
73 {
74         memset(xfs_etest, 0, sizeof(xfs_etest));
75         memset(xfs_etest_fsid, 0, sizeof(xfs_etest_fsid));
76         memset(xfs_etest_fsname, 0, sizeof(xfs_etest_fsname));
77 }
78
79 int
80 xfs_error_test(int error_tag, int *fsidp, char *expression,
81                int line, char *file, unsigned long randfactor)
82 {
83         int i;
84         int64_t fsid;
85
86         if (random() % randfactor)
87                 return 0;
88
89         memcpy(&fsid, fsidp, sizeof(xfs_fsid_t));
90
91         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
92                 if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) {
93                         cmn_err(CE_WARN,
94         "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
95                                 expression, file, line, xfs_etest_fsname[i]);
96                         return 1;
97                 }
98         }
99
100         return 0;
101 }
102
103 int
104 xfs_errortag_add(int error_tag, xfs_mount_t *mp)
105 {
106         int i;
107         int len;
108         int64_t fsid;
109
110         memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
111
112         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
113                 if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
114                         cmn_err(CE_WARN, "XFS error tag #%d on", error_tag);
115                         return 0;
116                 }
117         }
118
119         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
120                 if (xfs_etest[i] == 0) {
121                         cmn_err(CE_WARN, "Turned on XFS error tag #%d",
122                                 error_tag);
123                         xfs_etest[i] = error_tag;
124                         xfs_etest_fsid[i] = fsid;
125                         len = strlen(mp->m_fsname);
126                         xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP);
127                         strcpy(xfs_etest_fsname[i], mp->m_fsname);
128                         return 0;
129                 }
130         }
131
132         cmn_err(CE_WARN, "error tag overflow, too many turned on");
133
134         return 1;
135 }
136
137 int
138 xfs_errortag_clear(int error_tag, xfs_mount_t *mp)
139 {
140         int i;
141         int64_t fsid;
142
143         memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
144
145         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
146                 if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
147                         xfs_etest[i] = 0;
148                         xfs_etest_fsid[i] = 0LL;
149                         kmem_free(xfs_etest_fsname[i],
150                                   strlen(xfs_etest_fsname[i]) + 1);
151                         xfs_etest_fsname[i] = NULL;
152                         cmn_err(CE_WARN, "Cleared XFS error tag #%d",
153                                 error_tag);
154                         return 0;
155                 }
156         }
157
158         cmn_err(CE_WARN, "XFS error tag %d not on", error_tag);
159
160         return 1;
161 }
162
163 int
164 xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud)
165 {
166         int i;
167         int cleared = 0;
168
169         for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
170                 if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) &&
171                      xfs_etest[i] != 0) {
172                         cleared = 1;
173                         cmn_err(CE_WARN, "Clearing XFS error tag #%d",
174                                 xfs_etest[i]);
175                         xfs_etest[i] = 0;
176                         xfs_etest_fsid[i] = 0LL;
177                         kmem_free(xfs_etest_fsname[i],
178                                   strlen(xfs_etest_fsname[i]) + 1);
179                         xfs_etest_fsname[i] = NULL;
180                 }
181         }
182
183         if (loud || cleared)
184                 cmn_err(CE_WARN,
185                         "Cleared all XFS error tags for filesystem \"%s\"",
186                         fsname);
187
188         return 0;
189 }
190
191 int
192 xfs_errortag_clearall(xfs_mount_t *mp)
193 {
194         int64_t fsid;
195
196         memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
197
198         return xfs_errortag_clearall_umount(fsid, mp->m_fsname, 1);
199 }
200 #endif /* DEBUG || INDUCE_IO_ERROR */
201
202 static void
203 xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap)
204 {
205         if (mp != NULL) {
206                 char    *newfmt;
207                 int     len = 16 + mp->m_fsname_len + strlen(fmt);
208
209                 newfmt = kmem_alloc(len, KM_SLEEP);
210                 sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt);
211                 icmn_err(level, newfmt, ap);
212                 kmem_free(newfmt, len);
213         } else {
214                 icmn_err(level, fmt, ap);
215         }
216 }
217
218 void
219 xfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
220 {
221         va_list ap;
222
223         va_start(ap, fmt);
224         xfs_fs_vcmn_err(level, mp, fmt, ap);
225         va_end(ap);
226 }
227
228 void
229 xfs_cmn_err(int panic_tag, int level, xfs_mount_t *mp, char *fmt, ...)
230 {
231         va_list ap;
232
233 #ifdef DEBUG
234         xfs_panic_mask |= XFS_PTAG_SHUTDOWN_CORRUPT;
235 #endif
236
237         if (xfs_panic_mask && (xfs_panic_mask & panic_tag)
238             && (level & CE_ALERT)) {
239                 level &= ~CE_ALERT;
240                 level |= CE_PANIC;
241                 cmn_err(CE_ALERT, "XFS: Transforming an alert into a BUG.");
242         }
243         va_start(ap, fmt);
244         xfs_fs_vcmn_err(level, mp, fmt, ap);
245         va_end(ap);
246 }
247
248 void
249 xfs_error_report(
250         char            *tag,
251         int             level,
252         xfs_mount_t     *mp,
253         char            *fname,
254         int             linenum,
255         inst_t          *ra)
256 {
257         if (level <= xfs_error_level) {
258                 xfs_cmn_err(XFS_PTAG_ERROR_REPORT,
259                             CE_ALERT, mp,
260                 "XFS internal error %s at line %d of file %s.  Caller 0x%p\n",
261                             tag, linenum, fname, ra);
262
263                 xfs_stack_trace();
264         }
265 }
266
267 STATIC void
268 xfs_hex_dump(void *p, int length)
269 {
270         __uint8_t *uip = (__uint8_t*)p;
271         int     i;
272         char    sbuf[128], *s;
273
274         s = sbuf;
275         *s = '\0';
276         for (i=0; i<length; i++, uip++) {
277                 if ((i % 16) == 0) {
278                         if (*s != '\0')
279                                 cmn_err(CE_ALERT, "%s\n", sbuf);
280                         s = sbuf;
281                         sprintf(s, "0x%x: ", i);
282                         while( *s != '\0')
283                                 s++;
284                 }
285                 sprintf(s, "%02x ", *uip);
286
287                 /*
288                  * the kernel sprintf is a void; user sprintf returns
289                  * the sprintf'ed string's length.  Find the new end-
290                  * of-string
291                  */
292                 while( *s != '\0')
293                         s++;
294         }
295         cmn_err(CE_ALERT, "%s\n", sbuf);
296 }
297
298 void
299 xfs_corruption_error(
300         char            *tag,
301         int             level,
302         xfs_mount_t     *mp,
303         void            *p,
304         char            *fname,
305         int             linenum,
306         inst_t          *ra)
307 {
308         if (level <= xfs_error_level)
309                 xfs_hex_dump(p, 16);
310         xfs_error_report(tag, level, mp, fname, linenum, ra);
311 }