diff options
Diffstat (limited to 'mm/failslab.c')
| -rw-r--r-- | mm/failslab.c | 60 |
1 files changed, 38 insertions, 22 deletions
diff --git a/mm/failslab.c b/mm/failslab.c index fefaabaab76d..c3901b136498 100644 --- a/mm/failslab.c +++ b/mm/failslab.c @@ -1,29 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 #include <linux/fault-inject.h> +#include <linux/error-injection.h> +#include <linux/debugfs.h> #include <linux/slab.h> +#include <linux/mm.h> +#include "slab.h" static struct { struct fault_attr attr; - u32 ignore_gfp_wait; - int cache_filter; + bool ignore_gfp_reclaim; + bool cache_filter; } failslab = { .attr = FAULT_ATTR_INITIALIZER, - .ignore_gfp_wait = 1, - .cache_filter = 0, + .ignore_gfp_reclaim = true, + .cache_filter = false, }; -bool should_failslab(size_t size, gfp_t gfpflags, unsigned long cache_flags) +int should_failslab(struct kmem_cache *s, gfp_t gfpflags) { + int flags = 0; + + /* No fault-injection for bootstrap cache */ + if (unlikely(s == kmem_cache)) + return 0; + if (gfpflags & __GFP_NOFAIL) - return false; + return 0; - if (failslab.ignore_gfp_wait && (gfpflags & __GFP_WAIT)) - return false; + if (failslab.ignore_gfp_reclaim && + (gfpflags & __GFP_DIRECT_RECLAIM)) + return 0; - if (failslab.cache_filter && !(cache_flags & SLAB_FAILSLAB)) - return false; + if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB)) + return 0; - return should_fail(&failslab.attr, size); + /* + * In some cases, it expects to specify __GFP_NOWARN + * to avoid printing any information(not just a warning), + * thus avoiding deadlocks. See commit 6b9dbedbe349 for + * details. + */ + if (gfpflags & __GFP_NOWARN) + flags |= FAULT_NOWARN; + + return should_fail_ex(&failslab.attr, s->object_size, flags) ? -ENOMEM : 0; } +ALLOW_ERROR_INJECTION(should_failslab, ERRNO); static int __init setup_failslab(char *str) { @@ -35,24 +57,18 @@ __setup("failslab=", setup_failslab); static int __init failslab_debugfs_init(void) { struct dentry *dir; - umode_t mode = S_IFREG | S_IRUSR | S_IWUSR; + umode_t mode = S_IFREG | 0600; dir = fault_create_debugfs_attr("failslab", NULL, &failslab.attr); if (IS_ERR(dir)) return PTR_ERR(dir); - if (!debugfs_create_bool("ignore-gfp-wait", mode, dir, - &failslab.ignore_gfp_wait)) - goto fail; - if (!debugfs_create_bool("cache-filter", mode, dir, - &failslab.cache_filter)) - goto fail; + debugfs_create_bool("ignore-gfp-wait", mode, dir, + &failslab.ignore_gfp_reclaim); + debugfs_create_bool("cache-filter", mode, dir, + &failslab.cache_filter); return 0; -fail: - debugfs_remove_recursive(dir); - - return -ENOMEM; } late_initcall(failslab_debugfs_init); |
