aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkinobu Mita <akinobu.mita@gmail.com>2012-07-30 17:43:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 20:25:22 -0400
commit8d438288145f19f253a82ca71290b44fce79e23f (patch)
tree521c1086079ed8fb78aa622cf19bdbcfd53cbe12
parent1d151c337d79fa3de88654d2514f58fbd916a8e0 (diff)
fault-injection: notifier error injection
This patchset provides kernel modules that can be used to test the error handling of notifier call chain failures by injecting artifical errors to the following notifier chain callbacks. * CPU notifier * PM notifier * memory hotplug notifier * powerpc pSeries reconfig notifier Example: Inject CPU offline error (-1 == -EPERM) # cd /sys/kernel/debug/notifier-error-inject/cpu # echo -1 > actions/CPU_DOWN_PREPARE/error # echo 0 > /sys/devices/system/cpu/cpu1/online bash: echo: write error: Operation not permitted The patchset also adds cpu and memory hotplug tests to tools/testing/selftests These tests first do simple online and offline test and then do fault injection tests if notifier error injection module is available. This patch: The notifier error injection provides the ability to inject artifical errors to specified notifier chain callbacks. It is useful to test the error handling of notifier call chain failures. This adds common basic functions to define which type of events can be fail and to initialize the debugfs interface to control what error code should be returned and which event should be failed. Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> Cc: Pavel Machek <pavel@ucw.cz> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Cc: Greg KH <greg@kroah.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Michael Ellerman <michael@ellerman.id.au> Cc: Dave Jones <davej@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/fault-injection/notifier-error-inject.txt99
-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
5 files changed, 247 insertions, 0 deletions
diff --git a/Documentation/fault-injection/notifier-error-inject.txt b/Documentation/fault-injection/notifier-error-inject.txt
new file mode 100644
index 00000000000..c83526c364e
--- /dev/null
+++ b/Documentation/fault-injection/notifier-error-inject.txt
@@ -0,0 +1,99 @@
1Notifier error injection
2========================
3
4Notifier error injection provides the ability to inject artifical errors to
5specified notifier chain callbacks. It is useful to test the error handling of
6notifier call chain failures which is rarely executed. There are kernel
7modules that can be used to test the following notifiers.
8
9 * CPU notifier
10 * PM notifier
11 * Memory hotplug notifier
12 * powerpc pSeries reconfig notifier
13
14CPU notifier error injection module
15-----------------------------------
16This feature can be used to test the error handling of the CPU notifiers by
17injecting artifical errors to CPU notifier chain callbacks.
18
19If the notifier call chain should be failed with some events notified, write
20the error code to debugfs interface
21/sys/kernel/debug/notifier-error-inject/cpu/actions/<notifier event>/error
22
23Possible CPU notifier events to be failed are:
24
25 * CPU_UP_PREPARE
26 * CPU_UP_PREPARE_FROZEN
27 * CPU_DOWN_PREPARE
28 * CPU_DOWN_PREPARE_FROZEN
29
30Example1: Inject CPU offline error (-1 == -EPERM)
31
32 # cd /sys/kernel/debug/notifier-error-inject/cpu
33 # echo -1 > actions/CPU_DOWN_PREPARE/error
34 # echo 0 > /sys/devices/system/cpu/cpu1/online
35 bash: echo: write error: Operation not permitted
36
37Example2: inject CPU online error (-2 == -ENOENT)
38
39 # echo -2 > actions/CPU_UP_PREPARE/error
40 # echo 1 > /sys/devices/system/cpu/cpu1/online
41 bash: echo: write error: No such file or directory
42
43PM notifier error injection module
44----------------------------------
45This feature is controlled through debugfs interface
46/sys/kernel/debug/notifier-error-inject/pm/actions/<notifier event>/error
47
48Possible PM notifier events to be failed are:
49
50 * PM_HIBERNATION_PREPARE
51 * PM_SUSPEND_PREPARE
52 * PM_RESTORE_PREPARE
53
54Example: Inject PM suspend error (-12 = -ENOMEM)
55
56 # cd /sys/kernel/debug/notifier-error-inject/pm/
57 # echo -12 > actions/PM_SUSPEND_PREPARE/error
58 # echo mem > /sys/power/state
59 bash: echo: write error: Cannot allocate memory
60
61Memory hotplug notifier error injection module
62----------------------------------------------
63This feature is controlled through debugfs interface
64/sys/kernel/debug/notifier-error-inject/memory/actions/<notifier event>/error
65
66Possible memory notifier events to be failed are:
67
68 * MEM_GOING_ONLINE
69 * MEM_GOING_OFFLINE
70
71Example: Inject memory hotplug offline error (-12 == -ENOMEM)
72
73 # cd /sys/kernel/debug/notifier-error-inject/memory
74 # echo -12 > actions/MEM_GOING_OFFLINE/error
75 # echo offline > /sys/devices/system/memory/memoryXXX/state
76 bash: echo: write error: Cannot allocate memory
77
78powerpc pSeries reconfig notifier error injection module
79--------------------------------------------------------
80This feature is controlled through debugfs interface
81/sys/kernel/debug/notifier-error-inject/pSeries-reconfig/actions/<notifier event>/error
82
83Possible pSeries reconfig notifier events to be failed are:
84
85 * PSERIES_RECONFIG_ADD
86 * PSERIES_RECONFIG_REMOVE
87 * PSERIES_DRCONF_MEM_ADD
88 * PSERIES_DRCONF_MEM_REMOVE
89
90For more usage examples
91-----------------------
92There are tools/testing/selftests using the notifier error injection features
93for CPU and memory notifiers.
94
95 * tools/testing/selftests/cpu-hotplug/on-off-test.sh
96 * tools/testing/selftests/memory-hotplug/on-off-test.sh
97
98These scripts first do simple online and offline tests and then do fault
99injection tests if notifier error injection module is available.
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 4a186508bf8..bdee91d50a5 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 df663cc05c7..71acfa4489f 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 00000000000..44b92cb6224
--- /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 00000000000..99b3b6fc470
--- /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);