diff options
-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 | ||