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