aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig.debug11
-rw-r--r--lib/Makefile1
-rw-r--r--lib/notifier-error-inject.c112
-rw-r--r--lib/notifier-error-inject.h24
4 files changed, 148 insertions, 0 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 4a186508bf8b..bdee91d50a5b 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1084,6 +1084,17 @@ config LKDTM
1084 Documentation on how to use the module can be found in 1084 Documentation on how to use the module can be found in
1085 Documentation/fault-injection/provoke-crashes.txt 1085 Documentation/fault-injection/provoke-crashes.txt
1086 1086
1087config NOTIFIER_ERROR_INJECTION
1088 tristate "Notifier error injection"
1089 depends on DEBUG_KERNEL
1090 select DEBUG_FS
1091 help
1092 This option provides the ability to inject artifical errors to
1093 specified notifier chain callbacks. It is useful to test the error
1094 handling of notifier call chain failures.
1095
1096 Say N if unsure.
1097
1087config CPU_NOTIFIER_ERROR_INJECT 1098config CPU_NOTIFIER_ERROR_INJECT
1088 tristate "CPU notifier error injection module" 1099 tristate "CPU notifier error injection module"
1089 depends on HOTPLUG_CPU && DEBUG_KERNEL 1100 depends on HOTPLUG_CPU && DEBUG_KERNEL
diff --git a/lib/Makefile b/lib/Makefile
index df663cc05c73..71acfa4489f3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -90,6 +90,7 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o
90obj-$(CONFIG_SWIOTLB) += swiotlb.o 90obj-$(CONFIG_SWIOTLB) += swiotlb.o
91obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o 91obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
92obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o 92obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
93obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o
93obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o 94obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o
94 95
95lib-$(CONFIG_GENERIC_BUG) += bug.o 96lib-$(CONFIG_GENERIC_BUG) += bug.o
diff --git a/lib/notifier-error-inject.c b/lib/notifier-error-inject.c
new file mode 100644
index 000000000000..44b92cb6224f
--- /dev/null
+++ b/lib/notifier-error-inject.c
@@ -0,0 +1,112 @@
1#include <linux/module.h>
2
3#include "notifier-error-inject.h"
4
5static int debugfs_errno_set(void *data, u64 val)
6{
7 *(int *)data = clamp_t(int, val, -MAX_ERRNO, 0);
8 return 0;
9}
10
11static int debugfs_errno_get(void *data, u64 *val)
12{
13 *val = *(int *)data;
14 return 0;
15}
16
17DEFINE_SIMPLE_ATTRIBUTE(fops_errno, debugfs_errno_get, debugfs_errno_set,
18 "%lld\n");
19
20static struct dentry *debugfs_create_errno(const char *name, mode_t mode,
21 struct dentry *parent, int *value)
22{
23 return debugfs_create_file(name, mode, parent, value, &fops_errno);
24}
25
26static int notifier_err_inject_callback(struct notifier_block *nb,
27 unsigned long val, void *p)
28{
29 int err = 0;
30 struct notifier_err_inject *err_inject =
31 container_of(nb, struct notifier_err_inject, nb);
32 struct notifier_err_inject_action *action;
33
34 for (action = err_inject->actions; action->name; action++) {
35 if (action->val == val) {
36 err = action->error;
37 break;
38 }
39 }
40 if (err)
41 pr_info("Injecting error (%d) to %s\n", err, action->name);
42
43 return notifier_from_errno(err);
44}
45
46struct dentry *notifier_err_inject_dir;
47EXPORT_SYMBOL_GPL(notifier_err_inject_dir);
48
49struct dentry *notifier_err_inject_init(const char *name, struct dentry *parent,
50 struct notifier_err_inject *err_inject, int priority)
51{
52 struct notifier_err_inject_action *action;
53 mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
54 struct dentry *dir;
55 struct dentry *actions_dir;
56
57 err_inject->nb.notifier_call = notifier_err_inject_callback;
58 err_inject->nb.priority = priority;
59
60 dir = debugfs_create_dir(name, parent);
61 if (!dir)
62 return ERR_PTR(-ENOMEM);
63
64 actions_dir = debugfs_create_dir("actions", dir);
65 if (!actions_dir)
66 goto fail;
67
68 for (action = err_inject->actions; action->name; action++) {
69 struct dentry *action_dir;
70
71 action_dir = debugfs_create_dir(action->name, actions_dir);
72 if (!action_dir)
73 goto fail;
74
75 /*
76 * Create debugfs r/w file containing action->error. If
77 * notifier call chain is called with action->val, it will
78 * fail with the error code
79 */
80 if (!debugfs_create_errno("error", mode, action_dir,
81 &action->error))
82 goto fail;
83 }
84 return dir;
85fail:
86 debugfs_remove_recursive(dir);
87 return ERR_PTR(-ENOMEM);
88}
89EXPORT_SYMBOL_GPL(notifier_err_inject_init);
90
91static int __init err_inject_init(void)
92{
93 notifier_err_inject_dir =
94 debugfs_create_dir("notifier-error-inject", NULL);
95
96 if (!notifier_err_inject_dir)
97 return -ENOMEM;
98
99 return 0;
100}
101
102static void __exit err_inject_exit(void)
103{
104 debugfs_remove_recursive(notifier_err_inject_dir);
105}
106
107module_init(err_inject_init);
108module_exit(err_inject_exit);
109
110MODULE_DESCRIPTION("Notifier error injection module");
111MODULE_LICENSE("GPL");
112MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
diff --git a/lib/notifier-error-inject.h b/lib/notifier-error-inject.h
new file mode 100644
index 000000000000..99b3b6fc470b
--- /dev/null
+++ b/lib/notifier-error-inject.h
@@ -0,0 +1,24 @@
1#include <linux/atomic.h>
2#include <linux/debugfs.h>
3#include <linux/notifier.h>
4
5struct notifier_err_inject_action {
6 unsigned long val;
7 int error;
8 const char *name;
9};
10
11#define NOTIFIER_ERR_INJECT_ACTION(action) \
12 .name = #action, .val = (action),
13
14struct notifier_err_inject {
15 struct notifier_block nb;
16 struct notifier_err_inject_action actions[];
17 /* The last slot must be terminated with zero sentinel */
18};
19
20extern struct dentry *notifier_err_inject_dir;
21
22extern struct dentry *notifier_err_inject_init(const char *name,
23 struct dentry *parent, struct notifier_err_inject *err_inject,
24 int priority);