diff options
| author | Akinobu Mita <akinobu.mita@gmail.com> | 2006-12-08 05:39:43 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 11:29:02 -0500 |
| commit | 6ff1cb355e628f8fc55fa2d01e269e5e1bbc2fe9 (patch) | |
| tree | 393d94b6d7585e4c804d6415afaa11e1d6ec350d /lib | |
| parent | de1ba09b214056365d9082982905b255caafb7a2 (diff) | |
[PATCH] fault-injection capabilities infrastructure
This patch provides base functions implement to fault-injection
capabilities.
- The function should_fail() is taken from failmalloc-1.0
(http://www.nongnu.org/failmalloc/)
[akpm@osdl.org: cleanups, comments, add __init]
Cc: <okuji@enbug.org>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: Don Mullis <dwm@meer.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Kconfig.debug | 12 | ||||
| -rw-r--r-- | lib/Makefile | 1 | ||||
| -rw-r--r-- | lib/fault-inject.c | 183 |
3 files changed, 196 insertions, 0 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2c133c098607..35228b3e7e92 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
| @@ -413,3 +413,15 @@ config LKDTM | |||
| 413 | 413 | ||
| 414 | Documentation on how to use the module can be found in | 414 | Documentation on how to use the module can be found in |
| 415 | drivers/misc/lkdtm.c | 415 | drivers/misc/lkdtm.c |
| 416 | |||
| 417 | config FAULT_INJECTION | ||
| 418 | bool | ||
| 419 | |||
| 420 | config FAULT_INJECTION_DEBUG_FS | ||
| 421 | bool "Debugfs entries for fault-injection capabilities" | ||
| 422 | depends on FAULT_INJECTION && SYSFS | ||
| 423 | select DEBUG_FS | ||
| 424 | help | ||
| 425 | This option enable configuration of fault-injection capabilities via | ||
| 426 | debugfs. | ||
| 427 | |||
diff --git a/lib/Makefile b/lib/Makefile index 6f675c6149a7..2d6106af53cd 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
| @@ -55,6 +55,7 @@ obj-$(CONFIG_SMP) += percpu_counter.o | |||
| 55 | obj-$(CONFIG_AUDIT_GENERIC) += audit.o | 55 | obj-$(CONFIG_AUDIT_GENERIC) += audit.o |
| 56 | 56 | ||
| 57 | obj-$(CONFIG_SWIOTLB) += swiotlb.o | 57 | obj-$(CONFIG_SWIOTLB) += swiotlb.o |
| 58 | obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o | ||
| 58 | 59 | ||
| 59 | lib-$(CONFIG_GENERIC_BUG) += bug.o | 60 | lib-$(CONFIG_GENERIC_BUG) += bug.o |
| 60 | 61 | ||
diff --git a/lib/fault-inject.c b/lib/fault-inject.c new file mode 100644 index 000000000000..a7cb3afd132a --- /dev/null +++ b/lib/fault-inject.c | |||
| @@ -0,0 +1,183 @@ | |||
| 1 | #include <linux/kernel.h> | ||
| 2 | #include <linux/init.h> | ||
| 3 | #include <linux/random.h> | ||
| 4 | #include <linux/stat.h> | ||
| 5 | #include <linux/types.h> | ||
| 6 | #include <linux/fs.h> | ||
| 7 | #include <linux/module.h> | ||
| 8 | #include <linux/fault-inject.h> | ||
| 9 | |||
| 10 | /* | ||
| 11 | * setup_fault_attr() is a helper function for various __setup handlers, so it | ||
| 12 | * returns 0 on error, because that is what __setup handlers do. | ||
| 13 | */ | ||
| 14 | int __init setup_fault_attr(struct fault_attr *attr, char *str) | ||
| 15 | { | ||
| 16 | unsigned long probability; | ||
| 17 | unsigned long interval; | ||
| 18 | int times; | ||
| 19 | int space; | ||
| 20 | |||
| 21 | /* "<interval>,<probability>,<space>,<times>" */ | ||
| 22 | if (sscanf(str, "%lu,%lu,%d,%d", | ||
| 23 | &interval, &probability, &space, ×) < 4) { | ||
| 24 | printk(KERN_WARNING | ||
| 25 | "FAULT_INJECTION: failed to parse arguments\n"); | ||
| 26 | return 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | attr->probability = probability; | ||
| 30 | attr->interval = interval; | ||
| 31 | atomic_set(&attr->times, times); | ||
| 32 | atomic_set(&attr->space, space); | ||
| 33 | |||
| 34 | return 1; | ||
| 35 | } | ||
| 36 | |||
| 37 | static void fail_dump(struct fault_attr *attr) | ||
| 38 | { | ||
| 39 | if (attr->verbose > 0) | ||
| 40 | printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure\n"); | ||
| 41 | if (attr->verbose > 1) | ||
| 42 | dump_stack(); | ||
| 43 | } | ||
| 44 | |||
| 45 | #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) | ||
| 46 | |||
| 47 | /* | ||
| 48 | * This code is stolen from failmalloc-1.0 | ||
| 49 | * http://www.nongnu.org/failmalloc/ | ||
| 50 | */ | ||
| 51 | |||
| 52 | int should_fail(struct fault_attr *attr, ssize_t size) | ||
| 53 | { | ||
| 54 | if (atomic_read(&attr->times) == 0) | ||
| 55 | return 0; | ||
| 56 | |||
| 57 | if (atomic_read(&attr->space) > size) { | ||
| 58 | atomic_sub(size, &attr->space); | ||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | if (attr->interval > 1) { | ||
| 63 | attr->count++; | ||
| 64 | if (attr->count % attr->interval) | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | if (attr->probability > random32() % 100) | ||
| 69 | goto fail; | ||
| 70 | |||
| 71 | return 0; | ||
| 72 | |||
| 73 | fail: | ||
| 74 | fail_dump(attr); | ||
| 75 | |||
| 76 | if (atomic_read(&attr->times) != -1) | ||
| 77 | atomic_dec_not_zero(&attr->times); | ||
| 78 | |||
| 79 | return 1; | ||
| 80 | } | ||
| 81 | |||
| 82 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
| 83 | |||
| 84 | static void debugfs_ul_set(void *data, u64 val) | ||
| 85 | { | ||
| 86 | *(unsigned long *)data = val; | ||
| 87 | } | ||
| 88 | |||
| 89 | static u64 debugfs_ul_get(void *data) | ||
| 90 | { | ||
| 91 | return *(unsigned long *)data; | ||
| 92 | } | ||
| 93 | |||
| 94 | DEFINE_SIMPLE_ATTRIBUTE(fops_ul, debugfs_ul_get, debugfs_ul_set, "%llu\n"); | ||
| 95 | |||
| 96 | static struct dentry *debugfs_create_ul(const char *name, mode_t mode, | ||
| 97 | struct dentry *parent, unsigned long *value) | ||
| 98 | { | ||
| 99 | return debugfs_create_file(name, mode, parent, value, &fops_ul); | ||
| 100 | } | ||
| 101 | |||
| 102 | static void debugfs_atomic_t_set(void *data, u64 val) | ||
| 103 | { | ||
| 104 | atomic_set((atomic_t *)data, val); | ||
| 105 | } | ||
| 106 | |||
| 107 | static u64 debugfs_atomic_t_get(void *data) | ||
| 108 | { | ||
| 109 | return atomic_read((atomic_t *)data); | ||
| 110 | } | ||
| 111 | |||
| 112 | DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, | ||
| 113 | debugfs_atomic_t_set, "%lld\n"); | ||
| 114 | |||
| 115 | static struct dentry *debugfs_create_atomic_t(const char *name, mode_t mode, | ||
| 116 | struct dentry *parent, atomic_t *value) | ||
| 117 | { | ||
| 118 | return debugfs_create_file(name, mode, parent, value, &fops_atomic_t); | ||
| 119 | } | ||
| 120 | |||
| 121 | void cleanup_fault_attr_dentries(struct fault_attr *attr) | ||
| 122 | { | ||
| 123 | debugfs_remove(attr->dentries.probability_file); | ||
| 124 | attr->dentries.probability_file = NULL; | ||
| 125 | |||
| 126 | debugfs_remove(attr->dentries.interval_file); | ||
| 127 | attr->dentries.interval_file = NULL; | ||
| 128 | |||
| 129 | debugfs_remove(attr->dentries.times_file); | ||
| 130 | attr->dentries.times_file = NULL; | ||
| 131 | |||
| 132 | debugfs_remove(attr->dentries.space_file); | ||
| 133 | attr->dentries.space_file = NULL; | ||
| 134 | |||
| 135 | debugfs_remove(attr->dentries.verbose_file); | ||
| 136 | attr->dentries.verbose_file = NULL; | ||
| 137 | |||
| 138 | if (attr->dentries.dir) | ||
| 139 | WARN_ON(!simple_empty(attr->dentries.dir)); | ||
| 140 | |||
| 141 | debugfs_remove(attr->dentries.dir); | ||
| 142 | attr->dentries.dir = NULL; | ||
| 143 | } | ||
| 144 | |||
| 145 | int init_fault_attr_dentries(struct fault_attr *attr, const char *name) | ||
| 146 | { | ||
| 147 | mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; | ||
| 148 | struct dentry *dir; | ||
| 149 | |||
| 150 | memset(&attr->dentries, 0, sizeof(attr->dentries)); | ||
| 151 | |||
| 152 | dir = debugfs_create_dir(name, NULL); | ||
| 153 | if (!dir) | ||
| 154 | goto fail; | ||
| 155 | attr->dentries.dir = dir; | ||
| 156 | |||
| 157 | attr->dentries.probability_file = | ||
| 158 | debugfs_create_ul("probability", mode, dir, &attr->probability); | ||
| 159 | |||
| 160 | attr->dentries.interval_file = | ||
| 161 | debugfs_create_ul("interval", mode, dir, &attr->interval); | ||
| 162 | |||
| 163 | attr->dentries.times_file = | ||
| 164 | debugfs_create_atomic_t("times", mode, dir, &attr->times); | ||
| 165 | |||
| 166 | attr->dentries.space_file = | ||
| 167 | debugfs_create_atomic_t("space", mode, dir, &attr->space); | ||
| 168 | |||
| 169 | attr->dentries.verbose_file = | ||
| 170 | debugfs_create_ul("verbose", mode, dir, &attr->verbose); | ||
| 171 | |||
| 172 | if (!attr->dentries.probability_file || !attr->dentries.interval_file | ||
| 173 | || !attr->dentries.times_file || !attr->dentries.space_file | ||
| 174 | || !attr->dentries.verbose_file) | ||
| 175 | goto fail; | ||
| 176 | |||
| 177 | return 0; | ||
| 178 | fail: | ||
| 179 | cleanup_fault_attr_dentries(attr); | ||
| 180 | return -ENOMEM; | ||
| 181 | } | ||
| 182 | |||
| 183 | #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
