2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-07-31 01:43:02 +04:00
# include <linux/module.h>
# include "notifier-error-inject.h"
static int debugfs_errno_set ( void * data , u64 val )
{
* ( int * ) data = clamp_t ( int , val , - MAX_ERRNO , 0 ) ;
return 0 ;
}
static int debugfs_errno_get ( void * data , u64 * val )
{
* val = * ( int * ) data ;
return 0 ;
}
2022-09-19 20:24:17 +03:00
DEFINE_SIMPLE_ATTRIBUTE_SIGNED ( fops_errno , debugfs_errno_get , debugfs_errno_set ,
2012-07-31 01:43:02 +04:00
" %lld \n " ) ;
2013-03-29 20:23:28 +04:00
static struct dentry * debugfs_create_errno ( const char * name , umode_t mode ,
2012-07-31 01:43:02 +04:00
struct dentry * parent , int * value )
{
return debugfs_create_file ( name , mode , parent , value , & fops_errno ) ;
}
static int notifier_err_inject_callback ( struct notifier_block * nb ,
unsigned long val , void * p )
{
int err = 0 ;
struct notifier_err_inject * err_inject =
container_of ( nb , struct notifier_err_inject , nb ) ;
struct notifier_err_inject_action * action ;
for ( action = err_inject - > actions ; action - > name ; action + + ) {
if ( action - > val = = val ) {
err = action - > error ;
break ;
}
}
if ( err )
pr_info ( " Injecting error (%d) to %s \n " , err , action - > name ) ;
return notifier_from_errno ( err ) ;
}
struct dentry * notifier_err_inject_dir ;
EXPORT_SYMBOL_GPL ( notifier_err_inject_dir ) ;
struct dentry * notifier_err_inject_init ( const char * name , struct dentry * parent ,
struct notifier_err_inject * err_inject , int priority )
{
struct notifier_err_inject_action * action ;
2013-03-29 20:23:28 +04:00
umode_t mode = S_IFREG | S_IRUSR | S_IWUSR ;
2012-07-31 01:43:02 +04:00
struct dentry * dir ;
struct dentry * actions_dir ;
err_inject - > nb . notifier_call = notifier_err_inject_callback ;
err_inject - > nb . priority = priority ;
dir = debugfs_create_dir ( name , parent ) ;
actions_dir = debugfs_create_dir ( " actions " , dir ) ;
for ( action = err_inject - > actions ; action - > name ; action + + ) {
struct dentry * action_dir ;
action_dir = debugfs_create_dir ( action - > name , actions_dir ) ;
/*
* Create debugfs r / w file containing action - > error . If
* notifier call chain is called with action - > val , it will
* fail with the error code
*/
2019-06-12 18:36:13 +03:00
debugfs_create_errno ( " error " , mode , action_dir , & action - > error ) ;
2012-07-31 01:43:02 +04:00
}
return dir ;
}
EXPORT_SYMBOL_GPL ( notifier_err_inject_init ) ;
static int __init err_inject_init ( void )
{
notifier_err_inject_dir =
debugfs_create_dir ( " notifier-error-inject " , NULL ) ;
if ( ! notifier_err_inject_dir )
return - ENOMEM ;
return 0 ;
}
static void __exit err_inject_exit ( void )
{
debugfs_remove_recursive ( notifier_err_inject_dir ) ;
}
module_init ( err_inject_init ) ;
module_exit ( err_inject_exit ) ;
MODULE_DESCRIPTION ( " Notifier error injection module " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Akinobu Mita <akinobu.mita@gmail.com> " ) ;