18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/fault-inject.h>
38c2ecf20Sopenharmony_ci#include <linux/slab.h>
48c2ecf20Sopenharmony_ci#include <linux/mm.h>
58c2ecf20Sopenharmony_ci#include "slab.h"
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_cistatic struct {
88c2ecf20Sopenharmony_ci	struct fault_attr attr;
98c2ecf20Sopenharmony_ci	bool ignore_gfp_reclaim;
108c2ecf20Sopenharmony_ci	bool cache_filter;
118c2ecf20Sopenharmony_ci} failslab = {
128c2ecf20Sopenharmony_ci	.attr = FAULT_ATTR_INITIALIZER,
138c2ecf20Sopenharmony_ci	.ignore_gfp_reclaim = true,
148c2ecf20Sopenharmony_ci	.cache_filter = false,
158c2ecf20Sopenharmony_ci};
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cibool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	/* No fault-injection for bootstrap cache */
208c2ecf20Sopenharmony_ci	if (unlikely(s == kmem_cache))
218c2ecf20Sopenharmony_ci		return false;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	if (gfpflags & __GFP_NOFAIL)
248c2ecf20Sopenharmony_ci		return false;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (failslab.ignore_gfp_reclaim &&
278c2ecf20Sopenharmony_ci			(gfpflags & __GFP_DIRECT_RECLAIM))
288c2ecf20Sopenharmony_ci		return false;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB))
318c2ecf20Sopenharmony_ci		return false;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	return should_fail(&failslab.attr, s->object_size);
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int __init setup_failslab(char *str)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	return setup_fault_attr(&failslab.attr, str);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci__setup("failslab=", setup_failslab);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
438c2ecf20Sopenharmony_cistatic int __init failslab_debugfs_init(void)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct dentry *dir;
468c2ecf20Sopenharmony_ci	umode_t mode = S_IFREG | 0600;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	dir = fault_create_debugfs_attr("failslab", NULL, &failslab.attr);
498c2ecf20Sopenharmony_ci	if (IS_ERR(dir))
508c2ecf20Sopenharmony_ci		return PTR_ERR(dir);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	debugfs_create_bool("ignore-gfp-wait", mode, dir,
538c2ecf20Sopenharmony_ci			    &failslab.ignore_gfp_reclaim);
548c2ecf20Sopenharmony_ci	debugfs_create_bool("cache-filter", mode, dir,
558c2ecf20Sopenharmony_ci			    &failslab.cache_filter);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	return 0;
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cilate_initcall(failslab_debugfs_init);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
63