aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/vm/slub.txt1
-rw-r--r--include/linux/fault-inject.h5
-rw-r--r--include/linux/slab.h5
-rw-r--r--mm/failslab.c18
-rw-r--r--mm/slab.c2
-rw-r--r--mm/slub.c29
6 files changed, 52 insertions, 8 deletions
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
index b37300edf27..07375e73981 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 06ca9b21dad..7b64ad40e4c 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
85extern bool should_failslab(size_t size, gfp_t gfpflags); 85extern bool should_failslab(size_t size, gfp_t gfpflags, unsigned long flags);
86#else 86#else
87static inline bool should_failslab(size_t size, gfp_t gfpflags) 87static 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 2da8372519f..488446289ca 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 9339de5f0a9..bb41f98dd8b 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 7451bdacaf1..33496b70485 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 8d71aaf888d..cab5288736c 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