diff options
author | Akinobu Mita <akinobu.mita@gmail.com> | 2006-12-08 05:39:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 11:29:02 -0500 |
commit | 8a8b6502fb669c3a0638a08955442814cedc86b1 (patch) | |
tree | 2e49652f904eb821f2fa7ae8cab0dd9b756772d9 | |
parent | 6ff1cb355e628f8fc55fa2d01e269e5e1bbc2fe9 (diff) |
[PATCH] fault-injection capability for kmalloc
This patch provides fault-injection capability for kmalloc.
Boot option:
failslab=<interval>,<probability>,<space>,<times>
<interval> -- specifies the interval of failures.
<probability> -- specifies how often it should fail in percent.
<space> -- specifies the size of free space where memory can be
allocated safely in bytes.
<times> -- specifies how many times failures may happen at most.
Debugfs:
/debug/failslab/interval
/debug/failslab/probability
/debug/failslab/specifies
/debug/failslab/times
/debug/failslab/ignore-gfp-highmem
/debug/failslab/ignore-gfp-wait
Example:
failslab=10,100,0,-1
slab allocation (kmalloc(), kmem_cache_alloc(),..) fails once per 10 times.
Cc: Pekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | Documentation/fault-injection/fault-injection.txt | 2 | ||||
-rw-r--r-- | lib/Kconfig.debug | 7 | ||||
-rw-r--r-- | mm/slab.c | 77 |
3 files changed, 84 insertions, 2 deletions
diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt index 260ce6c199ce..cf075c20eda0 100644 --- a/Documentation/fault-injection/fault-injection.txt +++ b/Documentation/fault-injection/fault-injection.txt | |||
@@ -86,7 +86,6 @@ configuration of fault-injection capabilities. | |||
86 | specifies the maximum stacktrace depth walked during search | 86 | specifies the maximum stacktrace depth walked during search |
87 | for a caller within [address-start,address-end). | 87 | for a caller within [address-start,address-end). |
88 | 88 | ||
89 | - /debug/failslab/ignore-gfp-highmem: | ||
90 | - /debug/fail_page_alloc/ignore-gfp-highmem: | 89 | - /debug/fail_page_alloc/ignore-gfp-highmem: |
91 | 90 | ||
92 | Format: { 0 | 1 } | 91 | Format: { 0 | 1 } |
@@ -167,7 +166,6 @@ echo 10 > /debug/$FAILNAME/probability | |||
167 | echo 100 > /debug/$FAILNAME/interval | 166 | echo 100 > /debug/$FAILNAME/interval |
168 | echo -1 > /debug/$FAILNAME/times | 167 | echo -1 > /debug/$FAILNAME/times |
169 | echo 2 > /debug/$FAILNAME/verbose | 168 | echo 2 > /debug/$FAILNAME/verbose |
170 | echo 1 > /debug/$FAILNAME/ignore-gfp-highmem | ||
171 | echo 1 > /debug/$FAILNAME/ignore-gfp-wait | 169 | echo 1 > /debug/$FAILNAME/ignore-gfp-wait |
172 | 170 | ||
173 | blacklist() | 171 | blacklist() |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 35228b3e7e92..c7f567a57d7d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -417,6 +417,13 @@ config LKDTM | |||
417 | config FAULT_INJECTION | 417 | config FAULT_INJECTION |
418 | bool | 418 | bool |
419 | 419 | ||
420 | config FAILSLAB | ||
421 | bool "Fault-injection capabilitiy for kmalloc" | ||
422 | depends on DEBUG_KERNEL | ||
423 | select FAULT_INJECTION | ||
424 | help | ||
425 | This option provides fault-injection capabilitiy for kmalloc. | ||
426 | |||
420 | config FAULT_INJECTION_DEBUG_FS | 427 | config FAULT_INJECTION_DEBUG_FS |
421 | bool "Debugfs entries for fault-injection capabilities" | 428 | bool "Debugfs entries for fault-injection capabilities" |
422 | depends on FAULT_INJECTION && SYSFS | 429 | depends on FAULT_INJECTION && SYSFS |
@@ -107,6 +107,7 @@ | |||
107 | #include <linux/nodemask.h> | 107 | #include <linux/nodemask.h> |
108 | #include <linux/mempolicy.h> | 108 | #include <linux/mempolicy.h> |
109 | #include <linux/mutex.h> | 109 | #include <linux/mutex.h> |
110 | #include <linux/fault-inject.h> | ||
110 | #include <linux/rtmutex.h> | 111 | #include <linux/rtmutex.h> |
111 | 112 | ||
112 | #include <asm/cacheflush.h> | 113 | #include <asm/cacheflush.h> |
@@ -3088,12 +3089,88 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep, | |||
3088 | #define cache_alloc_debugcheck_after(a,b,objp,d) (objp) | 3089 | #define cache_alloc_debugcheck_after(a,b,objp,d) (objp) |
3089 | #endif | 3090 | #endif |
3090 | 3091 | ||
3092 | #ifdef CONFIG_FAILSLAB | ||
3093 | |||
3094 | static struct failslab_attr { | ||
3095 | |||
3096 | struct fault_attr attr; | ||
3097 | |||
3098 | u32 ignore_gfp_wait; | ||
3099 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
3100 | struct dentry *ignore_gfp_wait_file; | ||
3101 | #endif | ||
3102 | |||
3103 | } failslab = { | ||
3104 | .attr = FAULT_ATTR_INITIALIZER, | ||
3105 | }; | ||
3106 | |||
3107 | static int __init setup_failslab(char *str) | ||
3108 | { | ||
3109 | return setup_fault_attr(&failslab.attr, str); | ||
3110 | } | ||
3111 | __setup("failslab=", setup_failslab); | ||
3112 | |||
3113 | static int should_failslab(struct kmem_cache *cachep, gfp_t flags) | ||
3114 | { | ||
3115 | if (cachep == &cache_cache) | ||
3116 | return 0; | ||
3117 | if (flags & __GFP_NOFAIL) | ||
3118 | return 0; | ||
3119 | if (failslab.ignore_gfp_wait && (flags & __GFP_WAIT)) | ||
3120 | return 0; | ||
3121 | |||
3122 | return should_fail(&failslab.attr, obj_size(cachep)); | ||
3123 | } | ||
3124 | |||
3125 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
3126 | |||
3127 | static int __init failslab_debugfs(void) | ||
3128 | { | ||
3129 | mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; | ||
3130 | struct dentry *dir; | ||
3131 | int err; | ||
3132 | |||
3133 | err = init_fault_attr_dentries(&failslab.attr, "failslab"); | ||
3134 | if (err) | ||
3135 | return err; | ||
3136 | dir = failslab.attr.dentries.dir; | ||
3137 | |||
3138 | failslab.ignore_gfp_wait_file = | ||
3139 | debugfs_create_bool("ignore-gfp-wait", mode, dir, | ||
3140 | &failslab.ignore_gfp_wait); | ||
3141 | |||
3142 | if (!failslab.ignore_gfp_wait_file) { | ||
3143 | err = -ENOMEM; | ||
3144 | debugfs_remove(failslab.ignore_gfp_wait_file); | ||
3145 | cleanup_fault_attr_dentries(&failslab.attr); | ||
3146 | } | ||
3147 | |||
3148 | return err; | ||
3149 | } | ||
3150 | |||
3151 | late_initcall(failslab_debugfs); | ||
3152 | |||
3153 | #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
3154 | |||
3155 | #else /* CONFIG_FAILSLAB */ | ||
3156 | |||
3157 | static inline int should_failslab(struct kmem_cache *cachep, gfp_t flags) | ||
3158 | { | ||
3159 | return 0; | ||
3160 | } | ||
3161 | |||
3162 | #endif /* CONFIG_FAILSLAB */ | ||
3163 | |||
3091 | static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) | 3164 | static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) |
3092 | { | 3165 | { |
3093 | void *objp; | 3166 | void *objp; |
3094 | struct array_cache *ac; | 3167 | struct array_cache *ac; |
3095 | 3168 | ||
3096 | check_irq_off(); | 3169 | check_irq_off(); |
3170 | |||
3171 | if (should_failslab(cachep, flags)) | ||
3172 | return NULL; | ||
3173 | |||
3097 | ac = cpu_cache_get(cachep); | 3174 | ac = cpu_cache_get(cachep); |
3098 | if (likely(ac->avail)) { | 3175 | if (likely(ac->avail)) { |
3099 | STATS_INC_ALLOCHIT(cachep); | 3176 | STATS_INC_ALLOCHIT(cachep); |