diff options
author | Dmitry Monakhov <dmonakhov@openvz.org> | 2010-02-26 01:36:12 -0500 |
---|---|---|
committer | Pekka Enberg <penberg@cs.helsinki.fi> | 2010-02-26 12:19:39 -0500 |
commit | 4c13dd3b48fcb6fbe44f241eb11a057ecd1cba75 (patch) | |
tree | d9875477b9eb48ad598da8cbc36b473c941828ae | |
parent | 60b341b778cc2929df16c0a504c91621b3c6a4ad (diff) |
failslab: add ability to filter slab caches
This patch allow to inject faults only for specific slabs.
In order to preserve default behavior cache filter is off by
default (all caches are faulty).
One may define specific set of slabs like this:
# mark skbuff_head_cache as faulty
echo 1 > /sys/kernel/slab/skbuff_head_cache/failslab
# Turn on cache filter (off by default)
echo 1 > /sys/kernel/debug/failslab/cache-filter
# Turn on fault injection
echo 1 > /sys/kernel/debug/failslab/times
echo 1 > /sys/kernel/debug/failslab/probability
Acked-by: David Rientjes <rientjes@google.com>
Acked-by: Akinobu Mita <akinobu.mita@gmail.com>
Acked-by: Christoph Lameter <cl@linux-foundation.org>
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
-rw-r--r-- | Documentation/vm/slub.txt | 1 | ||||
-rw-r--r-- | include/linux/fault-inject.h | 5 | ||||
-rw-r--r-- | include/linux/slab.h | 5 | ||||
-rw-r--r-- | mm/failslab.c | 18 | ||||
-rw-r--r-- | mm/slab.c | 2 | ||||
-rw-r--r-- | mm/slub.c | 29 |
6 files changed, 52 insertions, 8 deletions
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt index b37300edf27c..07375e73981a 100644 --- a/Documentation/vm/slub.txt +++ b/Documentation/vm/slub.txt | |||
@@ -41,6 +41,7 @@ Possible debug options are | |||
41 | P Poisoning (object and padding) | 41 | P Poisoning (object and padding) |
42 | U User tracking (free and alloc) | 42 | U User tracking (free and alloc) |
43 | T Trace (please only use on single slabs) | 43 | T Trace (please only use on single slabs) |
44 | A Toggle failslab filter mark for the cache | ||
44 | O Switch debugging off for caches that would have | 45 | O Switch debugging off for caches that would have |
45 | caused higher minimum slab orders | 46 | caused higher minimum slab orders |
46 | - Switch all debugging off (useful if the kernel is | 47 | - Switch all debugging off (useful if the kernel is |
diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h index 06ca9b21dad2..7b64ad40e4ce 100644 --- a/include/linux/fault-inject.h +++ b/include/linux/fault-inject.h | |||
@@ -82,9 +82,10 @@ static inline void cleanup_fault_attr_dentries(struct fault_attr *attr) | |||
82 | #endif /* CONFIG_FAULT_INJECTION */ | 82 | #endif /* CONFIG_FAULT_INJECTION */ |
83 | 83 | ||
84 | #ifdef CONFIG_FAILSLAB | 84 | #ifdef CONFIG_FAILSLAB |
85 | extern bool should_failslab(size_t size, gfp_t gfpflags); | 85 | extern bool should_failslab(size_t size, gfp_t gfpflags, unsigned long flags); |
86 | #else | 86 | #else |
87 | static inline bool should_failslab(size_t size, gfp_t gfpflags) | 87 | static inline bool should_failslab(size_t size, gfp_t gfpflags, |
88 | unsigned long flags) | ||
88 | { | 89 | { |
89 | return false; | 90 | return false; |
90 | } | 91 | } |
diff --git a/include/linux/slab.h b/include/linux/slab.h index 2da8372519f5..488446289cab 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h | |||
@@ -70,6 +70,11 @@ | |||
70 | #else | 70 | #else |
71 | # define SLAB_NOTRACK 0x00000000UL | 71 | # define SLAB_NOTRACK 0x00000000UL |
72 | #endif | 72 | #endif |
73 | #ifdef CONFIG_FAILSLAB | ||
74 | # define SLAB_FAILSLAB 0x02000000UL /* Fault injection mark */ | ||
75 | #else | ||
76 | # define SLAB_FAILSLAB 0x00000000UL | ||
77 | #endif | ||
73 | 78 | ||
74 | /* The following flags affect the page allocator grouping pages by mobility */ | 79 | /* The following flags affect the page allocator grouping pages by mobility */ |
75 | #define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ | 80 | #define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ |
diff --git a/mm/failslab.c b/mm/failslab.c index 9339de5f0a91..bb41f98dd8b7 100644 --- a/mm/failslab.c +++ b/mm/failslab.c | |||
@@ -1,18 +1,22 @@ | |||
1 | #include <linux/fault-inject.h> | 1 | #include <linux/fault-inject.h> |
2 | #include <linux/gfp.h> | 2 | #include <linux/gfp.h> |
3 | #include <linux/slab.h> | ||
3 | 4 | ||
4 | static struct { | 5 | static struct { |
5 | struct fault_attr attr; | 6 | struct fault_attr attr; |
6 | u32 ignore_gfp_wait; | 7 | u32 ignore_gfp_wait; |
8 | int cache_filter; | ||
7 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | 9 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS |
8 | struct dentry *ignore_gfp_wait_file; | 10 | struct dentry *ignore_gfp_wait_file; |
11 | struct dentry *cache_filter_file; | ||
9 | #endif | 12 | #endif |
10 | } failslab = { | 13 | } failslab = { |
11 | .attr = FAULT_ATTR_INITIALIZER, | 14 | .attr = FAULT_ATTR_INITIALIZER, |
12 | .ignore_gfp_wait = 1, | 15 | .ignore_gfp_wait = 1, |
16 | .cache_filter = 0, | ||
13 | }; | 17 | }; |
14 | 18 | ||
15 | bool should_failslab(size_t size, gfp_t gfpflags) | 19 | bool should_failslab(size_t size, gfp_t gfpflags, unsigned long cache_flags) |
16 | { | 20 | { |
17 | if (gfpflags & __GFP_NOFAIL) | 21 | if (gfpflags & __GFP_NOFAIL) |
18 | return false; | 22 | return false; |
@@ -20,6 +24,9 @@ bool should_failslab(size_t size, gfp_t gfpflags) | |||
20 | if (failslab.ignore_gfp_wait && (gfpflags & __GFP_WAIT)) | 24 | if (failslab.ignore_gfp_wait && (gfpflags & __GFP_WAIT)) |
21 | return false; | 25 | return false; |
22 | 26 | ||
27 | if (failslab.cache_filter && !(cache_flags & SLAB_FAILSLAB)) | ||
28 | return false; | ||
29 | |||
23 | return should_fail(&failslab.attr, size); | 30 | return should_fail(&failslab.attr, size); |
24 | } | 31 | } |
25 | 32 | ||
@@ -30,7 +37,6 @@ static int __init setup_failslab(char *str) | |||
30 | __setup("failslab=", setup_failslab); | 37 | __setup("failslab=", setup_failslab); |
31 | 38 | ||
32 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | 39 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS |
33 | |||
34 | static int __init failslab_debugfs_init(void) | 40 | static int __init failslab_debugfs_init(void) |
35 | { | 41 | { |
36 | mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; | 42 | mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; |
@@ -46,8 +52,14 @@ static int __init failslab_debugfs_init(void) | |||
46 | debugfs_create_bool("ignore-gfp-wait", mode, dir, | 52 | debugfs_create_bool("ignore-gfp-wait", mode, dir, |
47 | &failslab.ignore_gfp_wait); | 53 | &failslab.ignore_gfp_wait); |
48 | 54 | ||
49 | if (!failslab.ignore_gfp_wait_file) { | 55 | failslab.cache_filter_file = |
56 | debugfs_create_bool("cache-filter", mode, dir, | ||
57 | &failslab.cache_filter); | ||
58 | |||
59 | if (!failslab.ignore_gfp_wait_file || | ||
60 | !failslab.cache_filter_file) { | ||
50 | err = -ENOMEM; | 61 | err = -ENOMEM; |
62 | debugfs_remove(failslab.cache_filter_file); | ||
51 | debugfs_remove(failslab.ignore_gfp_wait_file); | 63 | debugfs_remove(failslab.ignore_gfp_wait_file); |
52 | cleanup_fault_attr_dentries(&failslab.attr); | 64 | cleanup_fault_attr_dentries(&failslab.attr); |
53 | } | 65 | } |
@@ -3101,7 +3101,7 @@ static bool slab_should_failslab(struct kmem_cache *cachep, gfp_t flags) | |||
3101 | if (cachep == &cache_cache) | 3101 | if (cachep == &cache_cache) |
3102 | return false; | 3102 | return false; |
3103 | 3103 | ||
3104 | return should_failslab(obj_size(cachep), flags); | 3104 | return should_failslab(obj_size(cachep), flags, cachep->flags); |
3105 | } | 3105 | } |
3106 | 3106 | ||
3107 | static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) | 3107 | static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) |
@@ -151,7 +151,8 @@ | |||
151 | * Set of flags that will prevent slab merging | 151 | * Set of flags that will prevent slab merging |
152 | */ | 152 | */ |
153 | #define SLUB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ | 153 | #define SLUB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ |
154 | SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE) | 154 | SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \ |
155 | SLAB_FAILSLAB) | ||
155 | 156 | ||
156 | #define SLUB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \ | 157 | #define SLUB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \ |
157 | SLAB_CACHE_DMA | SLAB_NOTRACK) | 158 | SLAB_CACHE_DMA | SLAB_NOTRACK) |
@@ -1020,6 +1021,9 @@ static int __init setup_slub_debug(char *str) | |||
1020 | case 't': | 1021 | case 't': |
1021 | slub_debug |= SLAB_TRACE; | 1022 | slub_debug |= SLAB_TRACE; |
1022 | break; | 1023 | break; |
1024 | case 'a': | ||
1025 | slub_debug |= SLAB_FAILSLAB; | ||
1026 | break; | ||
1023 | default: | 1027 | default: |
1024 | printk(KERN_ERR "slub_debug option '%c' " | 1028 | printk(KERN_ERR "slub_debug option '%c' " |
1025 | "unknown. skipped\n", *str); | 1029 | "unknown. skipped\n", *str); |
@@ -1718,7 +1722,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s, | |||
1718 | lockdep_trace_alloc(gfpflags); | 1722 | lockdep_trace_alloc(gfpflags); |
1719 | might_sleep_if(gfpflags & __GFP_WAIT); | 1723 | might_sleep_if(gfpflags & __GFP_WAIT); |
1720 | 1724 | ||
1721 | if (should_failslab(s->objsize, gfpflags)) | 1725 | if (should_failslab(s->objsize, gfpflags, s->flags)) |
1722 | return NULL; | 1726 | return NULL; |
1723 | 1727 | ||
1724 | local_irq_save(flags); | 1728 | local_irq_save(flags); |
@@ -4171,6 +4175,23 @@ static ssize_t trace_store(struct kmem_cache *s, const char *buf, | |||
4171 | } | 4175 | } |
4172 | SLAB_ATTR(trace); | 4176 | SLAB_ATTR(trace); |
4173 | 4177 | ||
4178 | #ifdef CONFIG_FAILSLAB | ||
4179 | static ssize_t failslab_show(struct kmem_cache *s, char *buf) | ||
4180 | { | ||
4181 | return sprintf(buf, "%d\n", !!(s->flags & SLAB_FAILSLAB)); | ||
4182 | } | ||
4183 | |||
4184 | static ssize_t failslab_store(struct kmem_cache *s, const char *buf, | ||
4185 | size_t length) | ||
4186 | { | ||
4187 | s->flags &= ~SLAB_FAILSLAB; | ||
4188 | if (buf[0] == '1') | ||
4189 | s->flags |= SLAB_FAILSLAB; | ||
4190 | return length; | ||
4191 | } | ||
4192 | SLAB_ATTR(failslab); | ||
4193 | #endif | ||
4194 | |||
4174 | static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf) | 4195 | static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf) |
4175 | { | 4196 | { |
4176 | return sprintf(buf, "%d\n", !!(s->flags & SLAB_RECLAIM_ACCOUNT)); | 4197 | return sprintf(buf, "%d\n", !!(s->flags & SLAB_RECLAIM_ACCOUNT)); |
@@ -4467,6 +4488,10 @@ static struct attribute *slab_attrs[] = { | |||
4467 | &deactivate_remote_frees_attr.attr, | 4488 | &deactivate_remote_frees_attr.attr, |
4468 | &order_fallback_attr.attr, | 4489 | &order_fallback_attr.attr, |
4469 | #endif | 4490 | #endif |
4491 | #ifdef CONFIG_FAILSLAB | ||
4492 | &failslab_attr.attr, | ||
4493 | #endif | ||
4494 | |||
4470 | NULL | 4495 | NULL |
4471 | }; | 4496 | }; |
4472 | 4497 | ||