Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Akinobu Mita and committed by
Linus Torvalds
8d438288 1d151c33

+247
+99
Documentation/fault-injection/notifier-error-inject.txt
··· 1 + Notifier error injection 2 + ======================== 3 + 4 + Notifier error injection provides the ability to inject artifical errors to 5 + specified notifier chain callbacks. It is useful to test the error handling of 6 + notifier call chain failures which is rarely executed. There are kernel 7 + modules 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 + 14 + CPU notifier error injection module 15 + ----------------------------------- 16 + This feature can be used to test the error handling of the CPU notifiers by 17 + injecting artifical errors to CPU notifier chain callbacks. 18 + 19 + If the notifier call chain should be failed with some events notified, write 20 + the error code to debugfs interface 21 + /sys/kernel/debug/notifier-error-inject/cpu/actions/<notifier event>/error 22 + 23 + Possible 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 + 30 + Example1: 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 + 37 + Example2: 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 + 43 + PM notifier error injection module 44 + ---------------------------------- 45 + This feature is controlled through debugfs interface 46 + /sys/kernel/debug/notifier-error-inject/pm/actions/<notifier event>/error 47 + 48 + Possible PM notifier events to be failed are: 49 + 50 + * PM_HIBERNATION_PREPARE 51 + * PM_SUSPEND_PREPARE 52 + * PM_RESTORE_PREPARE 53 + 54 + Example: 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 + 61 + Memory hotplug notifier error injection module 62 + ---------------------------------------------- 63 + This feature is controlled through debugfs interface 64 + /sys/kernel/debug/notifier-error-inject/memory/actions/<notifier event>/error 65 + 66 + Possible memory notifier events to be failed are: 67 + 68 + * MEM_GOING_ONLINE 69 + * MEM_GOING_OFFLINE 70 + 71 + Example: 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 + 78 + powerpc pSeries reconfig notifier error injection module 79 + -------------------------------------------------------- 80 + This feature is controlled through debugfs interface 81 + /sys/kernel/debug/notifier-error-inject/pSeries-reconfig/actions/<notifier event>/error 82 + 83 + Possible 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 + 90 + For more usage examples 91 + ----------------------- 92 + There are tools/testing/selftests using the notifier error injection features 93 + for 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 + 98 + These scripts first do simple online and offline tests and then do fault 99 + injection tests if notifier error injection module is available.
+11
lib/Kconfig.debug
··· 1084 1084 Documentation on how to use the module can be found in 1085 1085 Documentation/fault-injection/provoke-crashes.txt 1086 1086 1087 + config 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 + 1087 1098 config CPU_NOTIFIER_ERROR_INJECT 1088 1099 tristate "CPU notifier error injection module" 1089 1100 depends on HOTPLUG_CPU && DEBUG_KERNEL
+1
lib/Makefile
··· 90 90 obj-$(CONFIG_SWIOTLB) += swiotlb.o 91 91 obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o 92 92 obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o 93 + obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o 93 94 obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o 94 95 95 96 lib-$(CONFIG_GENERIC_BUG) += bug.o
+112
lib/notifier-error-inject.c
··· 1 + #include <linux/module.h> 2 + 3 + #include "notifier-error-inject.h" 4 + 5 + static int debugfs_errno_set(void *data, u64 val) 6 + { 7 + *(int *)data = clamp_t(int, val, -MAX_ERRNO, 0); 8 + return 0; 9 + } 10 + 11 + static int debugfs_errno_get(void *data, u64 *val) 12 + { 13 + *val = *(int *)data; 14 + return 0; 15 + } 16 + 17 + DEFINE_SIMPLE_ATTRIBUTE(fops_errno, debugfs_errno_get, debugfs_errno_set, 18 + "%lld\n"); 19 + 20 + static 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 + 26 + static 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 + 46 + struct dentry *notifier_err_inject_dir; 47 + EXPORT_SYMBOL_GPL(notifier_err_inject_dir); 48 + 49 + struct 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; 85 + fail: 86 + debugfs_remove_recursive(dir); 87 + return ERR_PTR(-ENOMEM); 88 + } 89 + EXPORT_SYMBOL_GPL(notifier_err_inject_init); 90 + 91 + static 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 + 102 + static void __exit err_inject_exit(void) 103 + { 104 + debugfs_remove_recursive(notifier_err_inject_dir); 105 + } 106 + 107 + module_init(err_inject_init); 108 + module_exit(err_inject_exit); 109 + 110 + MODULE_DESCRIPTION("Notifier error injection module"); 111 + MODULE_LICENSE("GPL"); 112 + MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
+24
lib/notifier-error-inject.h
··· 1 + #include <linux/atomic.h> 2 + #include <linux/debugfs.h> 3 + #include <linux/notifier.h> 4 + 5 + struct 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 + 14 + struct 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 + 20 + extern struct dentry *notifier_err_inject_dir; 21 + 22 + extern struct dentry *notifier_err_inject_init(const char *name, 23 + struct dentry *parent, struct notifier_err_inject *err_inject, 24 + int priority);