0001
0002 #include <linux/module.h>
0003
0004 #include "notifier-error-inject.h"
0005
0006 static int debugfs_errno_set(void *data, u64 val)
0007 {
0008 *(int *)data = clamp_t(int, val, -MAX_ERRNO, 0);
0009 return 0;
0010 }
0011
0012 static int debugfs_errno_get(void *data, u64 *val)
0013 {
0014 *val = *(int *)data;
0015 return 0;
0016 }
0017
0018 DEFINE_SIMPLE_ATTRIBUTE(fops_errno, debugfs_errno_get, debugfs_errno_set,
0019 "%lld\n");
0020
0021 static struct dentry *debugfs_create_errno(const char *name, umode_t mode,
0022 struct dentry *parent, int *value)
0023 {
0024 return debugfs_create_file(name, mode, parent, value, &fops_errno);
0025 }
0026
0027 static int notifier_err_inject_callback(struct notifier_block *nb,
0028 unsigned long val, void *p)
0029 {
0030 int err = 0;
0031 struct notifier_err_inject *err_inject =
0032 container_of(nb, struct notifier_err_inject, nb);
0033 struct notifier_err_inject_action *action;
0034
0035 for (action = err_inject->actions; action->name; action++) {
0036 if (action->val == val) {
0037 err = action->error;
0038 break;
0039 }
0040 }
0041 if (err)
0042 pr_info("Injecting error (%d) to %s\n", err, action->name);
0043
0044 return notifier_from_errno(err);
0045 }
0046
0047 struct dentry *notifier_err_inject_dir;
0048 EXPORT_SYMBOL_GPL(notifier_err_inject_dir);
0049
0050 struct dentry *notifier_err_inject_init(const char *name, struct dentry *parent,
0051 struct notifier_err_inject *err_inject, int priority)
0052 {
0053 struct notifier_err_inject_action *action;
0054 umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
0055 struct dentry *dir;
0056 struct dentry *actions_dir;
0057
0058 err_inject->nb.notifier_call = notifier_err_inject_callback;
0059 err_inject->nb.priority = priority;
0060
0061 dir = debugfs_create_dir(name, parent);
0062
0063 actions_dir = debugfs_create_dir("actions", dir);
0064
0065 for (action = err_inject->actions; action->name; action++) {
0066 struct dentry *action_dir;
0067
0068 action_dir = debugfs_create_dir(action->name, actions_dir);
0069
0070
0071
0072
0073
0074
0075 debugfs_create_errno("error", mode, action_dir, &action->error);
0076 }
0077 return dir;
0078 }
0079 EXPORT_SYMBOL_GPL(notifier_err_inject_init);
0080
0081 static int __init err_inject_init(void)
0082 {
0083 notifier_err_inject_dir =
0084 debugfs_create_dir("notifier-error-inject", NULL);
0085
0086 if (!notifier_err_inject_dir)
0087 return -ENOMEM;
0088
0089 return 0;
0090 }
0091
0092 static void __exit err_inject_exit(void)
0093 {
0094 debugfs_remove_recursive(notifier_err_inject_dir);
0095 }
0096
0097 module_init(err_inject_init);
0098 module_exit(err_inject_exit);
0099
0100 MODULE_DESCRIPTION("Notifier error injection module");
0101 MODULE_LICENSE("GPL");
0102 MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");