aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2010-02-26 01:36:12 -0500
committerPekka Enberg <penberg@cs.helsinki.fi>2010-02-26 12:19:39 -0500
commit4c13dd3b48fcb6fbe44f241eb11a057ecd1cba75 (patch)
treed9875477b9eb48ad598da8cbc36b473c941828ae /mm
parent60b341b778cc2929df16c0a504c91621b3c6a4ad (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>
Diffstat (limited to 'mm')
-rw-r--r--mm/failslab.c18
-rw-r--r--mm/slab.c2
-rw-r--r--mm/slub.c29
3 files changed, 43 insertions, 6 deletions
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
4static struct { 5static 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
15bool should_failslab(size_t size, gfp_t gfpflags) 19bool 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
34static int __init failslab_debugfs_init(void) 40static 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 }
diff --git a/mm/slab.c b/mm/slab.c
index 7451bdacaf18..33496b704859 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -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
3107static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) 3107static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
diff --git a/mm/slub.c b/mm/slub.c
index 8d71aaf888d7..cab5288736c8 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -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}
4172SLAB_ATTR(trace); 4176SLAB_ATTR(trace);
4173 4177
4178#ifdef CONFIG_FAILSLAB
4179static ssize_t failslab_show(struct kmem_cache *s, char *buf)
4180{
4181 return sprintf(buf, "%d\n", !!(s->flags & SLAB_FAILSLAB));
4182}
4183
4184static 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}
4192SLAB_ATTR(failslab);
4193#endif
4194
4174static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf) 4195static 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