diff options
-rw-r--r-- | include/linux/fault-inject.h | 9 | ||||
-rw-r--r-- | lib/Kconfig.debug | 1 | ||||
-rw-r--r-- | mm/Makefile | 1 | ||||
-rw-r--r-- | mm/failslab.c | 59 | ||||
-rw-r--r-- | mm/slab.c | 75 | ||||
-rw-r--r-- | mm/slub.c | 5 |
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 | ||
85 | extern bool should_failslab(size_t size, gfp_t gfpflags); | ||
86 | #else | ||
87 | static 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 | |||
699 | config FAILSLAB | 699 | config 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 | |||
28 | obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o | 28 | obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o |
29 | obj-$(CONFIG_SLAB) += slab.o | 29 | obj-$(CONFIG_SLAB) += slab.o |
30 | obj-$(CONFIG_SLUB) += slub.o | 30 | obj-$(CONFIG_SLUB) += slub.o |
31 | obj-$(CONFIG_FAILSLAB) += failslab.o | ||
31 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o | 32 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o |
32 | obj-$(CONFIG_FS_XIP) += filemap_xip.o | 33 | obj-$(CONFIG_FS_XIP) += filemap_xip.o |
33 | obj-$(CONFIG_MIGRATION) += migrate.o | 34 | obj-$(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 | |||
3 | static 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 | |||
14 | bool 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 | |||
25 | static 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 | |||
33 | static 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 | |||
57 | late_initcall(failslab_debugfs_init); | ||
58 | |||
59 | #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
@@ -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 | 3111 | static bool slab_should_failslab(struct kmem_cache *cachep, gfp_t flags) |
3112 | |||
3113 | static 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 | |||
3127 | static int __init setup_failslab(char *str) | ||
3128 | { | ||
3129 | return setup_fault_attr(&failslab.attr, str); | ||
3130 | } | ||
3131 | __setup("failslab=", setup_failslab); | ||
3132 | |||
3133 | static 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 | |||
3147 | static 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 | |||
3171 | late_initcall(failslab_debugfs); | ||
3172 | |||
3173 | #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
3174 | |||
3175 | #else /* CONFIG_FAILSLAB */ | ||
3176 | |||
3177 | static inline int should_failslab(struct kmem_cache *cachep, gfp_t flags) | ||
3178 | { | ||
3179 | return 0; | ||
3180 | } | ||
3181 | |||
3182 | #endif /* CONFIG_FAILSLAB */ | ||
3183 | |||
3184 | static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) | 3119 | static 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); |
@@ -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; |