2018-06-06 05:42:14 +03:00
// SPDX-License-Identifier: GPL-2.0
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
*/
# include "xfs.h"
2019-06-29 05:25:35 +03:00
# include "xfs_shared.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"
2017-10-31 22:04:49 +03:00
# include "xfs_errortag.h"
2005-04-17 02:20:36 +04:00
# include "xfs_error.h"
2017-06-21 03:54:47 +03:00
# include "xfs_sysfs.h"
2018-01-23 05:09:48 +03:00
# include "xfs_inode.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-10-18 00:16:29 +03:00
XFS_RANDOM_BUF_LRU_REF ,
2018-05-14 16:34:36 +03:00
XFS_RANDOM_FORCE_SCRUB_REPAIR ,
2018-07-20 19:28:40 +03:00
XFS_RANDOM_FORCE_SUMMARY_RECALC ,
2019-02-07 21:37:16 +03:00
XFS_RANDOM_IUNLINK_FALLBACK ,
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-10-18 00:16:29 +03:00
XFS_ERRORTAG_ATTR_RW ( buf_lru_ref , XFS_ERRTAG_BUF_LRU_REF ) ;
2018-05-14 16:34:36 +03:00
XFS_ERRORTAG_ATTR_RW ( force_repair , XFS_ERRTAG_FORCE_SCRUB_REPAIR ) ;
2018-07-20 19:28:40 +03:00
XFS_ERRORTAG_ATTR_RW ( bad_summary , XFS_ERRTAG_FORCE_SUMMARY_RECALC ) ;
2019-02-07 21:37:16 +03:00
XFS_ERRORTAG_ATTR_RW ( iunlink_fallback , XFS_ERRTAG_IUNLINK_FALLBACK ) ;
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-10-18 00:16:29 +03:00
XFS_ERRORTAG_ATTR_LIST ( buf_lru_ref ) ,
2018-05-14 16:34:36 +03:00
XFS_ERRORTAG_ATTR_LIST ( force_repair ) ,
2018-07-20 19:28:40 +03:00
XFS_ERRORTAG_ATTR_LIST ( bad_summary ) ,
2019-02-07 21:37:16 +03:00
XFS_ERRORTAG_ATTR_LIST ( iunlink_fallback ) ,
2017-06-21 03:54:47 +03:00
NULL ,
} ;
2017-11-06 22:53:59 +03:00
static struct kobj_type xfs_errortag_ktype = {
2017-06-21 03:54:47 +03:00
. 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 ,
2018-01-08 21:51:25 +03:00
xfs_failaddr_t failaddr )
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 " ,
2018-01-08 21:51:25 +03:00
tag , linenum , filename , failaddr ) ;
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 ,
2018-06-04 20:23:54 +03:00
void * buf ,
size_t bufsize ,
2010-04-13 09:22:08 +04:00
const char * filename ,
int linenum ,
2018-01-08 21:51:25 +03:00
xfs_failaddr_t failaddr )
2005-04-17 02:20:36 +04:00
{
if ( level < = xfs_error_level )
2018-06-04 20:23:54 +03:00
xfs_hex_dump ( buf , bufsize ) ;
2018-01-08 21:51:25 +03:00
xfs_error_report ( tag , level , mp , filename , linenum , failaddr ) ;
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
2018-03-23 20:06:53 +03:00
xfs_buf_verifier_error (
2018-01-08 21:51:02 +03:00
struct xfs_buf * bp ,
2018-01-08 21:51:03 +03:00
int error ,
2018-03-23 20:06:53 +03:00
const char * name ,
void * buf ,
size_t bufsz ,
2018-01-08 21:51:03 +03:00
xfs_failaddr_t failaddr )
2014-02-27 08:21:07 +04:00
{
2018-01-08 21:51:03 +03:00
struct xfs_mount * mp = bp - > b_target - > bt_mount ;
xfs_failaddr_t fa ;
2018-03-23 20:06:53 +03:00
int sz ;
2014-02-27 08:21:07 +04:00
2018-01-08 21:51:03 +03:00
fa = failaddr ? failaddr : __return_address ;
__xfs_buf_ioerror ( bp , error , fa ) ;
2018-01-08 21:51:02 +03:00
2019-02-01 20:12:20 +03:00
xfs_alert_tag ( mp , XFS_PTAG_VERIFIER_ERROR ,
" Metadata %s detected at %pS, %s block 0x%llx %s " ,
2014-06-25 08:58:08 +04:00
bp - > b_error = = - EFSBADCRC ? " CRC error " : " corruption " ,
2018-03-23 20:06:53 +03:00
fa , bp - > b_ops - > name , bp - > b_bn , name ) ;
2014-02-27 08:21:07 +04:00
xfs_alert ( mp , " Unmount and run xfs_repair " ) ;
if ( xfs_error_level > = XFS_ERRLEVEL_LOW ) {
2018-03-23 20:06:53 +03:00
sz = min_t ( size_t , XFS_CORRUPTION_DUMP_LEN , bufsz ) ;
2018-01-08 21:51:26 +03:00
xfs_alert ( mp , " First %d bytes of corrupted metadata buffer: " ,
2018-03-23 20:06:53 +03:00
sz ) ;
xfs_hex_dump ( buf , sz ) ;
2014-02-27 08:21:07 +04:00
}
if ( xfs_error_level > = XFS_ERRLEVEL_HIGH )
xfs_stack_trace ( ) ;
}
2018-01-23 05:09:48 +03:00
2018-03-23 20:06:53 +03: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 ,
int error ,
xfs_failaddr_t failaddr )
{
return xfs_buf_verifier_error ( bp , error , " " , xfs_buf_offset ( bp , 0 ) ,
XFS_CORRUPTION_DUMP_LEN , failaddr ) ;
}
2018-01-23 05:09:48 +03:00
/*
* Warnings for inode corruption problems . Don ' t bother with the stack
* trace unless the error level is turned up high .
*/
void
xfs_inode_verifier_error (
struct xfs_inode * ip ,
int error ,
const char * name ,
void * buf ,
size_t bufsz ,
xfs_failaddr_t failaddr )
{
struct xfs_mount * mp = ip - > i_mount ;
xfs_failaddr_t fa ;
int sz ;
fa = failaddr ? failaddr : __return_address ;
xfs_alert ( mp , " Metadata %s detected at %pS, inode 0x%llx %s " ,
error = = - EFSBADCRC ? " CRC error " : " corruption " ,
fa , ip - > i_ino , name ) ;
xfs_alert ( mp , " Unmount and run xfs_repair " ) ;
if ( buf & & xfs_error_level > = XFS_ERRLEVEL_LOW ) {
sz = min_t ( size_t , XFS_CORRUPTION_DUMP_LEN , bufsz ) ;
xfs_alert ( mp , " First %d bytes of corrupted metadata buffer: " ,
sz ) ;
xfs_hex_dump ( buf , sz ) ;
}
if ( xfs_error_level > = XFS_ERRLEVEL_HIGH )
xfs_stack_trace ( ) ;
}