aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/fault-inject.h9
-rw-r--r--lib/Kconfig.debug1
-rw-r--r--mm/Makefile1
-rw-r--r--mm/failslab.c59
-rw-r--r--mm/slab.c75
-rw-r--r--mm/slub.c5
6 files changed, 80 insertions, 70 deletions
diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h
index 32368c4f0326..06ca9b21dad2 100644
--- a/include/linux/fault-inject.h
+++ b/include/linux/fault-inject.h
@@ -81,4 +81,13 @@ static inline void cleanup_fault_attr_dentries(struct fault_attr *attr)
81 81
82#endif /* CONFIG_FAULT_INJECTION */ 82#endif /* CONFIG_FAULT_INJECTION */
83 83
84#ifdef CONFIG_FAILSLAB
85extern bool should_failslab(size_t size, gfp_t gfpflags);
86#else
87static inline bool should_failslab(size_t size, gfp_t gfpflags)
88{
89 return false;
90}
91#endif /* CONFIG_FAILSLAB */
92
84#endif /* _LINUX_FAULT_INJECT_H */ 93#endif /* _LINUX_FAULT_INJECT_H */
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index b0f239e443bc..af65ae7f0549 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -699,6 +699,7 @@ config FAULT_INJECTION
699config FAILSLAB 699config FAILSLAB
700 bool "Fault-injection capability for kmalloc" 700 bool "Fault-injection capability for kmalloc"
701 depends on FAULT_INJECTION 701 depends on FAULT_INJECTION
702 depends on SLAB || SLUB
702 help 703 help
703 Provide fault-injection capability for kmalloc. 704 Provide fault-injection capability for kmalloc.
704 705
diff --git a/mm/Makefile b/mm/Makefile
index c06b45a1ff5f..51c27709cc7c 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_SLOB) += slob.o
28obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o 28obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
29obj-$(CONFIG_SLAB) += slab.o 29obj-$(CONFIG_SLAB) += slab.o
30obj-$(CONFIG_SLUB) += slub.o 30obj-$(CONFIG_SLUB) += slub.o
31obj-$(CONFIG_FAILSLAB) += failslab.o
31obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o 32obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
32obj-$(CONFIG_FS_XIP) += filemap_xip.o 33obj-$(CONFIG_FS_XIP) += filemap_xip.o
33obj-$(CONFIG_MIGRATION) += migrate.o 34obj-$(CONFIG_MIGRATION) += migrate.o
diff --git a/mm/failslab.c b/mm/failslab.c
new file mode 100644
index 000000000000..7c6ea6493f80
--- /dev/null
+++ b/mm/failslab.c
@@ -0,0 +1,59 @@
1#include <linux/fault-inject.h>
2
3static struct {
4 struct fault_attr attr;
5 u32 ignore_gfp_wait;
6#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
7 struct dentry *ignore_gfp_wait_file;
8#endif
9} failslab = {
10 .attr = FAULT_ATTR_INITIALIZER,
11 .ignore_gfp_wait = 1,
12};
13
14bool should_failslab(size_t size, gfp_t gfpflags)
15{
16 if (gfpflags & __GFP_NOFAIL)
17 return false;
18
19 if (failslab.ignore_gfp_wait && (gfpflags & __GFP_WAIT))
20 return false;
21
22 return should_fail(&failslab.attr, size);
23}
24
25static int __init setup_failslab(char *str)
26{
27 return setup_fault_attr(&failslab.attr, str);
28}
29__setup("failslab=", setup_failslab);
30
31#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
32
33static int __init failslab_debugfs_init(void)
34{
35 mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
36 struct dentry *dir;
37 int err;
38
39 err = init_fault_attr_dentries(&failslab.attr, "failslab");
40 if (err)
41 return err;
42 dir = failslab.attr.dentries.dir;
43
44 failslab.ignore_gfp_wait_file =
45 debugfs_create_bool("ignore-gfp-wait", mode, dir,
46 &failslab.ignore_gfp_wait);
47
48 if (!failslab.ignore_gfp_wait_file) {
49 err = -ENOMEM;
50 debugfs_remove(failslab.ignore_gfp_wait_file);
51 cleanup_fault_attr_dentries(&failslab.attr);
52 }
53
54 return err;
55}
56
57late_initcall(failslab_debugfs_init);
58
59#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
diff --git a/mm/slab.c b/mm/slab.c
index cb2e411d93a9..f97e564bdf11 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3108,79 +3108,14 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
3108#define cache_alloc_debugcheck_after(a,b,objp,d) (objp) 3108#define cache_alloc_debugcheck_after(a,b,objp,d) (objp)
3109#endif 3109#endif
3110 3110
3111#ifdef CONFIG_FAILSLAB 3111static bool slab_should_failslab(struct kmem_cache *cachep, gfp_t flags)
3112
3113static struct failslab_attr {
3114
3115 struct fault_attr attr;
3116
3117 u32 ignore_gfp_wait;
3118#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
3119 struct dentry *ignore_gfp_wait_file;
3120#endif
3121
3122} failslab = {
3123 .attr = FAULT_ATTR_INITIALIZER,
3124 .ignore_gfp_wait = 1,
3125};
3126
3127static int __init setup_failslab(char *str)
3128{
3129 return setup_fault_attr(&failslab.attr, str);
3130}
3131__setup("failslab=", setup_failslab);
3132
3133static int should_failslab(struct kmem_cache *cachep, gfp_t flags)
3134{ 3112{
3135 if (cachep == &cache_cache) 3113 if (cachep == &cache_cache)
3136 return 0; 3114 return false;
3137 if (flags & __GFP_NOFAIL)
3138 return 0;
3139 if (failslab.ignore_gfp_wait && (flags & __GFP_WAIT))
3140 return 0;
3141 3115
3142 return should_fail(&failslab.attr, obj_size(cachep)); 3116 return should_failslab(obj_size(cachep), flags);
3143} 3117}
3144 3118
3145#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
3146
3147static int __init failslab_debugfs(void)
3148{
3149 mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
3150 struct dentry *dir;
3151 int err;
3152
3153 err = init_fault_attr_dentries(&failslab.attr, "failslab");
3154 if (err)
3155 return err;
3156 dir = failslab.attr.dentries.dir;
3157
3158 failslab.ignore_gfp_wait_file =
3159 debugfs_create_bool("ignore-gfp-wait", mode, dir,
3160 &failslab.ignore_gfp_wait);
3161
3162 if (!failslab.ignore_gfp_wait_file) {
3163 err = -ENOMEM;
3164 debugfs_remove(failslab.ignore_gfp_wait_file);
3165 cleanup_fault_attr_dentries(&failslab.attr);
3166 }
3167
3168 return err;
3169}
3170
3171late_initcall(failslab_debugfs);
3172
3173#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
3174
3175#else /* CONFIG_FAILSLAB */
3176
3177static inline int should_failslab(struct kmem_cache *cachep, gfp_t flags)
3178{
3179 return 0;
3180}
3181
3182#endif /* CONFIG_FAILSLAB */
3183
3184static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) 3119static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
3185{ 3120{
3186 void *objp; 3121 void *objp;
@@ -3383,7 +3318,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
3383 unsigned long save_flags; 3318 unsigned long save_flags;
3384 void *ptr; 3319 void *ptr;
3385 3320
3386 if (should_failslab(cachep, flags)) 3321 if (slab_should_failslab(cachep, flags))
3387 return NULL; 3322 return NULL;
3388 3323
3389 cache_alloc_debugcheck_before(cachep, flags); 3324 cache_alloc_debugcheck_before(cachep, flags);
@@ -3459,7 +3394,7 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
3459 unsigned long save_flags; 3394 unsigned long save_flags;
3460 void *objp; 3395 void *objp;
3461 3396
3462 if (should_failslab(cachep, flags)) 3397 if (slab_should_failslab(cachep, flags))
3463 return NULL; 3398 return NULL;
3464 3399
3465 cache_alloc_debugcheck_before(cachep, flags); 3400 cache_alloc_debugcheck_before(cachep, flags);
diff --git a/mm/slub.c b/mm/slub.c
index ca95e45f04c3..6cb7ad107852 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -24,6 +24,7 @@
24#include <linux/kallsyms.h> 24#include <linux/kallsyms.h>
25#include <linux/memory.h> 25#include <linux/memory.h>
26#include <linux/math64.h> 26#include <linux/math64.h>
27#include <linux/fault-inject.h>
27 28
28/* 29/*
29 * Lock order: 30 * Lock order:
@@ -1596,6 +1597,10 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
1596 unsigned int objsize; 1597 unsigned int objsize;
1597 1598
1598 might_sleep_if(gfpflags & __GFP_WAIT); 1599 might_sleep_if(gfpflags & __GFP_WAIT);
1600
1601 if (should_failslab(s->objsize, gfpflags))
1602 return NULL;
1603
1599 local_irq_save(flags); 1604 local_irq_save(flags);
1600 c = get_cpu_slab(s, smp_processor_id()); 1605 c = get_cpu_slab(s, smp_processor_id());
1601 objsize = c->objsize; 1606 objsize = c->objsize;