2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* Copyright ( c ) 2000 - 2001 , 2005 Silicon Graphics , Inc .
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-17 02:20:36 +04:00
* published by the Free Software Foundation .
*
2005-11-02 06:58:39 +03:00
* This program is distributed in the hope that it would be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
2013-10-23 03:51:50 +04:00
# include "xfs_format.h"
2005-11-02 06:38:42 +03:00
# include "xfs_fs.h"
2013-10-23 03:50:10 +04:00
# include "xfs_log_format.h"
# include "xfs_trans_resv.h"
2005-04-17 02:20:36 +04:00
# include "xfs_mount.h"
# include "xfs_error.h"
2017-06-21 03:54:47 +03:00
# include "xfs_sysfs.h"
2005-04-17 02:20:36 +04:00
# ifdef DEBUG
2017-06-21 03:54:46 +03:00
static unsigned int xfs_errortag_random_default [ ] = {
XFS_RANDOM_DEFAULT ,
XFS_RANDOM_IFLUSH_1 ,
XFS_RANDOM_IFLUSH_2 ,
XFS_RANDOM_IFLUSH_3 ,
XFS_RANDOM_IFLUSH_4 ,
XFS_RANDOM_IFLUSH_5 ,
XFS_RANDOM_IFLUSH_6 ,
XFS_RANDOM_DA_READ_BUF ,
XFS_RANDOM_BTREE_CHECK_LBLOCK ,
XFS_RANDOM_BTREE_CHECK_SBLOCK ,
XFS_RANDOM_ALLOC_READ_AGF ,
XFS_RANDOM_IALLOC_READ_AGI ,
XFS_RANDOM_ITOBP_INOTOBP ,
XFS_RANDOM_IUNLINK ,
XFS_RANDOM_IUNLINK_REMOVE ,
XFS_RANDOM_DIR_INO_VALIDATE ,
XFS_RANDOM_BULKSTAT_READ_CHUNK ,
XFS_RANDOM_IODONE_IOERR ,
XFS_RANDOM_STRATREAD_IOERR ,
XFS_RANDOM_STRATCMPL_IOERR ,
XFS_RANDOM_DIOWRITE_IOERR ,
XFS_RANDOM_BMAPIFORMAT ,
XFS_RANDOM_FREE_EXTENT ,
XFS_RANDOM_RMAP_FINISH_ONE ,
XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE ,
XFS_RANDOM_REFCOUNT_FINISH_ONE ,
XFS_RANDOM_BMAP_FINISH_ONE ,
XFS_RANDOM_AG_RESV_CRITICAL ,
2017-06-21 03:54:48 +03:00
XFS_RANDOM_DROP_WRITES ,
2017-06-27 19:52:32 +03:00
XFS_RANDOM_LOG_BAD_CRC ,
2017-08-09 04:21:52 +03:00
XFS_RANDOM_LOG_ITEM_PIN ,
2017-06-21 03:54:46 +03:00
} ;
2005-04-17 02:20:36 +04:00
2017-06-21 03:54:47 +03:00
struct xfs_errortag_attr {
struct attribute attr ;
unsigned int tag ;
} ;
static inline struct xfs_errortag_attr *
to_attr ( struct attribute * attr )
{
return container_of ( attr , struct xfs_errortag_attr , attr ) ;
}
static inline struct xfs_mount *
to_mp ( struct kobject * kobject )
{
struct xfs_kobj * kobj = to_kobj ( kobject ) ;
return container_of ( kobj , struct xfs_mount , m_errortag_kobj ) ;
}
STATIC ssize_t
xfs_errortag_attr_store (
struct kobject * kobject ,
struct attribute * attr ,
const char * buf ,
size_t count )
{
struct xfs_mount * mp = to_mp ( kobject ) ;
struct xfs_errortag_attr * xfs_attr = to_attr ( attr ) ;
int ret ;
unsigned int val ;
if ( strcmp ( buf , " default " ) = = 0 ) {
val = xfs_errortag_random_default [ xfs_attr - > tag ] ;
} else {
ret = kstrtouint ( buf , 0 , & val ) ;
if ( ret )
return ret ;
}
ret = xfs_errortag_set ( mp , xfs_attr - > tag , val ) ;
if ( ret )
return ret ;
return count ;
}
STATIC ssize_t
xfs_errortag_attr_show (
struct kobject * kobject ,
struct attribute * attr ,
char * buf )
{
struct xfs_mount * mp = to_mp ( kobject ) ;
struct xfs_errortag_attr * xfs_attr = to_attr ( attr ) ;
return snprintf ( buf , PAGE_SIZE , " %u \n " ,
xfs_errortag_get ( mp , xfs_attr - > tag ) ) ;
}
static const struct sysfs_ops xfs_errortag_sysfs_ops = {
. show = xfs_errortag_attr_show ,
. store = xfs_errortag_attr_store ,
} ;
# define XFS_ERRORTAG_ATTR_RW(_name, _tag) \
static struct xfs_errortag_attr xfs_errortag_attr_ # # _name = { \
. attr = { . name = __stringify ( _name ) , \
. mode = VERIFY_OCTAL_PERMISSIONS ( S_IWUSR | S_IRUGO ) } , \
. tag = ( _tag ) , \
}
# define XFS_ERRORTAG_ATTR_LIST(_name) &xfs_errortag_attr_##_name.attr
XFS_ERRORTAG_ATTR_RW ( noerror , XFS_ERRTAG_NOERROR ) ;
XFS_ERRORTAG_ATTR_RW ( iflush1 , XFS_ERRTAG_IFLUSH_1 ) ;
XFS_ERRORTAG_ATTR_RW ( iflush2 , XFS_ERRTAG_IFLUSH_2 ) ;
XFS_ERRORTAG_ATTR_RW ( iflush3 , XFS_ERRTAG_IFLUSH_3 ) ;
XFS_ERRORTAG_ATTR_RW ( iflush4 , XFS_ERRTAG_IFLUSH_4 ) ;
XFS_ERRORTAG_ATTR_RW ( iflush5 , XFS_ERRTAG_IFLUSH_5 ) ;
XFS_ERRORTAG_ATTR_RW ( iflush6 , XFS_ERRTAG_IFLUSH_6 ) ;
XFS_ERRORTAG_ATTR_RW ( dareadbuf , XFS_ERRTAG_DA_READ_BUF ) ;
XFS_ERRORTAG_ATTR_RW ( btree_chk_lblk , XFS_ERRTAG_BTREE_CHECK_LBLOCK ) ;
XFS_ERRORTAG_ATTR_RW ( btree_chk_sblk , XFS_ERRTAG_BTREE_CHECK_SBLOCK ) ;
XFS_ERRORTAG_ATTR_RW ( readagf , XFS_ERRTAG_ALLOC_READ_AGF ) ;
XFS_ERRORTAG_ATTR_RW ( readagi , XFS_ERRTAG_IALLOC_READ_AGI ) ;
XFS_ERRORTAG_ATTR_RW ( itobp , XFS_ERRTAG_ITOBP_INOTOBP ) ;
XFS_ERRORTAG_ATTR_RW ( iunlink , XFS_ERRTAG_IUNLINK ) ;
XFS_ERRORTAG_ATTR_RW ( iunlinkrm , XFS_ERRTAG_IUNLINK_REMOVE ) ;
XFS_ERRORTAG_ATTR_RW ( dirinovalid , XFS_ERRTAG_DIR_INO_VALIDATE ) ;
XFS_ERRORTAG_ATTR_RW ( bulkstat , XFS_ERRTAG_BULKSTAT_READ_CHUNK ) ;
XFS_ERRORTAG_ATTR_RW ( logiodone , XFS_ERRTAG_IODONE_IOERR ) ;
XFS_ERRORTAG_ATTR_RW ( stratread , XFS_ERRTAG_STRATREAD_IOERR ) ;
XFS_ERRORTAG_ATTR_RW ( stratcmpl , XFS_ERRTAG_STRATCMPL_IOERR ) ;
XFS_ERRORTAG_ATTR_RW ( diowrite , XFS_ERRTAG_DIOWRITE_IOERR ) ;
XFS_ERRORTAG_ATTR_RW ( bmapifmt , XFS_ERRTAG_BMAPIFORMAT ) ;
XFS_ERRORTAG_ATTR_RW ( free_extent , XFS_ERRTAG_FREE_EXTENT ) ;
XFS_ERRORTAG_ATTR_RW ( rmap_finish_one , XFS_ERRTAG_RMAP_FINISH_ONE ) ;
XFS_ERRORTAG_ATTR_RW ( refcount_continue_update , XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE ) ;
XFS_ERRORTAG_ATTR_RW ( refcount_finish_one , XFS_ERRTAG_REFCOUNT_FINISH_ONE ) ;
XFS_ERRORTAG_ATTR_RW ( bmap_finish_one , XFS_ERRTAG_BMAP_FINISH_ONE ) ;
XFS_ERRORTAG_ATTR_RW ( ag_resv_critical , XFS_ERRTAG_AG_RESV_CRITICAL ) ;
2017-06-21 03:54:48 +03:00
XFS_ERRORTAG_ATTR_RW ( drop_writes , XFS_ERRTAG_DROP_WRITES ) ;
2017-06-27 19:52:32 +03:00
XFS_ERRORTAG_ATTR_RW ( log_bad_crc , XFS_ERRTAG_LOG_BAD_CRC ) ;
2017-08-09 04:21:52 +03:00
XFS_ERRORTAG_ATTR_RW ( log_item_pin , XFS_ERRTAG_LOG_ITEM_PIN ) ;
2017-06-21 03:54:47 +03:00
static struct attribute * xfs_errortag_attrs [ ] = {
XFS_ERRORTAG_ATTR_LIST ( noerror ) ,
XFS_ERRORTAG_ATTR_LIST ( iflush1 ) ,
XFS_ERRORTAG_ATTR_LIST ( iflush2 ) ,
XFS_ERRORTAG_ATTR_LIST ( iflush3 ) ,
XFS_ERRORTAG_ATTR_LIST ( iflush4 ) ,
XFS_ERRORTAG_ATTR_LIST ( iflush5 ) ,
XFS_ERRORTAG_ATTR_LIST ( iflush6 ) ,
XFS_ERRORTAG_ATTR_LIST ( dareadbuf ) ,
XFS_ERRORTAG_ATTR_LIST ( btree_chk_lblk ) ,
XFS_ERRORTAG_ATTR_LIST ( btree_chk_sblk ) ,
XFS_ERRORTAG_ATTR_LIST ( readagf ) ,
XFS_ERRORTAG_ATTR_LIST ( readagi ) ,
XFS_ERRORTAG_ATTR_LIST ( itobp ) ,
XFS_ERRORTAG_ATTR_LIST ( iunlink ) ,
XFS_ERRORTAG_ATTR_LIST ( iunlinkrm ) ,
XFS_ERRORTAG_ATTR_LIST ( dirinovalid ) ,
XFS_ERRORTAG_ATTR_LIST ( bulkstat ) ,
XFS_ERRORTAG_ATTR_LIST ( logiodone ) ,
XFS_ERRORTAG_ATTR_LIST ( stratread ) ,
XFS_ERRORTAG_ATTR_LIST ( stratcmpl ) ,
XFS_ERRORTAG_ATTR_LIST ( diowrite ) ,
XFS_ERRORTAG_ATTR_LIST ( bmapifmt ) ,
XFS_ERRORTAG_ATTR_LIST ( free_extent ) ,
XFS_ERRORTAG_ATTR_LIST ( rmap_finish_one ) ,
XFS_ERRORTAG_ATTR_LIST ( refcount_continue_update ) ,
XFS_ERRORTAG_ATTR_LIST ( refcount_finish_one ) ,
XFS_ERRORTAG_ATTR_LIST ( bmap_finish_one ) ,
XFS_ERRORTAG_ATTR_LIST ( ag_resv_critical ) ,
2017-06-21 03:54:48 +03:00
XFS_ERRORTAG_ATTR_LIST ( drop_writes ) ,
2017-06-27 19:52:32 +03:00
XFS_ERRORTAG_ATTR_LIST ( log_bad_crc ) ,
2017-08-09 04:21:52 +03:00
XFS_ERRORTAG_ATTR_LIST ( log_item_pin ) ,
2017-06-21 03:54:47 +03:00
NULL ,
} ;
struct kobj_type xfs_errortag_ktype = {
. release = xfs_sysfs_release ,
. sysfs_ops = & xfs_errortag_sysfs_ops ,
. default_attrs = xfs_errortag_attrs ,
} ;
2005-04-17 02:20:36 +04:00
int
2017-06-21 03:54:46 +03:00
xfs_errortag_init (
struct xfs_mount * mp )
2005-04-17 02:20:36 +04:00
{
2017-06-21 03:54:46 +03:00
mp - > m_errortag = kmem_zalloc ( sizeof ( unsigned int ) * XFS_ERRTAG_MAX ,
KM_SLEEP | KM_MAYFAIL ) ;
if ( ! mp - > m_errortag )
return - ENOMEM ;
2017-06-21 03:54:47 +03:00
return xfs_sysfs_init ( & mp - > m_errortag_kobj , & xfs_errortag_ktype ,
& mp - > m_kobj , " errortag " ) ;
2017-06-21 03:54:46 +03:00
}
2005-04-17 02:20:36 +04:00
2017-06-21 03:54:46 +03:00
void
xfs_errortag_del (
struct xfs_mount * mp )
{
2017-06-21 03:54:47 +03:00
xfs_sysfs_del ( & mp - > m_errortag_kobj ) ;
2017-06-21 03:54:46 +03:00
kmem_free ( mp - > m_errortag ) ;
}
2005-04-17 02:20:36 +04:00
2017-06-21 03:54:46 +03:00
bool
xfs_errortag_test (
struct xfs_mount * mp ,
const char * expression ,
const char * file ,
int line ,
unsigned int error_tag )
{
unsigned int randfactor ;
2005-04-17 02:20:36 +04:00
2017-06-30 19:46:07 +03:00
/*
* To be able to use error injection anywhere , we need to ensure error
* injection mechanism is already initialized .
*
* Code paths like I / O completion can be called before the
* initialization is complete , but be able to inject errors in such
* places is still useful .
*/
if ( ! mp - > m_errortag )
return false ;
2017-06-21 03:54:46 +03:00
ASSERT ( error_tag < XFS_ERRTAG_MAX ) ;
randfactor = mp - > m_errortag [ error_tag ] ;
if ( ! randfactor | | prandom_u32 ( ) % randfactor )
return false ;
2005-04-17 02:20:36 +04:00
2017-06-21 03:54:46 +03:00
xfs_warn_ratelimited ( mp ,
" Injecting error (%s) at file %s, line %d, on filesystem \" %s \" " ,
expression , file , line , mp - > m_fsname ) ;
return true ;
2005-04-17 02:20:36 +04:00
}
2017-06-21 03:54:47 +03:00
int
xfs_errortag_get (
struct xfs_mount * mp ,
unsigned int error_tag )
{
if ( error_tag > = XFS_ERRTAG_MAX )
return - EINVAL ;
return mp - > m_errortag [ error_tag ] ;
}
2005-04-17 02:20:36 +04:00
int
2017-06-21 03:54:46 +03:00
xfs_errortag_set (
struct xfs_mount * mp ,
unsigned int error_tag ,
unsigned int tag_value )
2005-04-17 02:20:36 +04:00
{
2016-06-21 04:53:28 +03:00
if ( error_tag > = XFS_ERRTAG_MAX )
return - EINVAL ;
2017-06-21 03:54:46 +03:00
mp - > m_errortag [ error_tag ] = tag_value ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
int
2017-06-21 03:54:46 +03:00
xfs_errortag_add (
struct xfs_mount * mp ,
unsigned int error_tag )
2005-04-17 02:20:36 +04:00
{
2017-06-21 03:54:46 +03:00
if ( error_tag > = XFS_ERRTAG_MAX )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2017-06-21 03:54:46 +03:00
return xfs_errortag_set ( mp , error_tag ,
xfs_errortag_random_default [ error_tag ] ) ;
}
2005-04-17 02:20:36 +04:00
2017-06-21 03:54:46 +03:00
int
xfs_errortag_clearall (
struct xfs_mount * mp )
{
memset ( mp - > m_errortag , 0 , sizeof ( unsigned int ) * XFS_ERRTAG_MAX ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-08-13 10:17:37 +04:00
# endif /* DEBUG */
2005-04-17 02:20:36 +04:00
void
xfs_error_report (
2010-04-13 09:22:08 +04:00
const char * tag ,
int level ,
struct xfs_mount * mp ,
const char * filename ,
int linenum ,
2015-06-22 02:44:02 +03:00
void * ra )
2005-04-17 02:20:36 +04:00
{
if ( level < = xfs_error_level ) {
2011-03-07 02:02:35 +03:00
xfs_alert_tag ( mp , XFS_PTAG_ERROR_REPORT ,
2015-03-25 06:56:21 +03:00
" Internal error %s at line %d of file %s. Caller %pS " ,
2010-04-13 09:22:08 +04:00
tag , linenum , filename , ra ) ;
2005-04-17 02:20:36 +04:00
xfs_stack_trace ( ) ;
}
}
void
xfs_corruption_error (
2010-04-13 09:22:08 +04:00
const char * tag ,
int level ,
struct xfs_mount * mp ,
void * p ,
const char * filename ,
int linenum ,
2015-06-22 02:44:02 +03:00
void * ra )
2005-04-17 02:20:36 +04:00
{
if ( level < = xfs_error_level )
2013-04-03 09:11:11 +04:00
xfs_hex_dump ( p , 64 ) ;
2010-04-13 09:22:08 +04:00
xfs_error_report ( tag , level , mp , filename , linenum , ra ) ;
2011-03-07 02:03:35 +03:00
xfs_alert ( mp , " Corruption detected. Unmount and run xfs_repair " ) ;
2005-04-17 02:20:36 +04:00
}
2014-02-27 08:21:07 +04:00
/*
* Warnings specifically for verifier errors . Differentiate CRC vs . invalid
* values , and omit the stack trace unless the error level is tuned high .
*/
void
xfs_verifier_error (
struct xfs_buf * bp )
{
struct xfs_mount * mp = bp - > b_target - > bt_mount ;
2017-09-18 21:34:16 +03:00
xfs_alert ( mp , " Metadata %s detected at %pS, %s block 0x%llx " ,
2014-06-25 08:58:08 +04:00
bp - > b_error = = - EFSBADCRC ? " CRC error " : " corruption " ,
2016-01-04 08:10:19 +03:00
__return_address , bp - > b_ops - > name , bp - > b_bn ) ;
2014-02-27 08:21:07 +04:00
xfs_alert ( mp , " Unmount and run xfs_repair " ) ;
if ( xfs_error_level > = XFS_ERRLEVEL_LOW ) {
xfs_alert ( mp , " First 64 bytes of corrupted metadata buffer: " ) ;
xfs_hex_dump ( xfs_buf_offset ( bp , 0 ) , 64 ) ;
}
if ( xfs_error_level > = XFS_ERRLEVEL_HIGH )
xfs_stack_trace ( ) ;
}