162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/fault-inject.h> 362306a36Sopenharmony_ci#include <linux/slab.h> 462306a36Sopenharmony_ci#include <linux/mm.h> 562306a36Sopenharmony_ci#include "slab.h" 662306a36Sopenharmony_ci 762306a36Sopenharmony_cistatic struct { 862306a36Sopenharmony_ci struct fault_attr attr; 962306a36Sopenharmony_ci bool ignore_gfp_reclaim; 1062306a36Sopenharmony_ci bool cache_filter; 1162306a36Sopenharmony_ci} failslab = { 1262306a36Sopenharmony_ci .attr = FAULT_ATTR_INITIALIZER, 1362306a36Sopenharmony_ci .ignore_gfp_reclaim = true, 1462306a36Sopenharmony_ci .cache_filter = false, 1562306a36Sopenharmony_ci}; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cibool __should_failslab(struct kmem_cache *s, gfp_t gfpflags) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci int flags = 0; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci /* No fault-injection for bootstrap cache */ 2262306a36Sopenharmony_ci if (unlikely(s == kmem_cache)) 2362306a36Sopenharmony_ci return false; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci if (gfpflags & __GFP_NOFAIL) 2662306a36Sopenharmony_ci return false; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (failslab.ignore_gfp_reclaim && 2962306a36Sopenharmony_ci (gfpflags & __GFP_DIRECT_RECLAIM)) 3062306a36Sopenharmony_ci return false; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB)) 3362306a36Sopenharmony_ci return false; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* 3662306a36Sopenharmony_ci * In some cases, it expects to specify __GFP_NOWARN 3762306a36Sopenharmony_ci * to avoid printing any information(not just a warning), 3862306a36Sopenharmony_ci * thus avoiding deadlocks. See commit 6b9dbedbe349 for 3962306a36Sopenharmony_ci * details. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci if (gfpflags & __GFP_NOWARN) 4262306a36Sopenharmony_ci flags |= FAULT_NOWARN; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return should_fail_ex(&failslab.attr, s->object_size, flags); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int __init setup_failslab(char *str) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci return setup_fault_attr(&failslab.attr, str); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci__setup("failslab=", setup_failslab); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS 5462306a36Sopenharmony_cistatic int __init failslab_debugfs_init(void) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct dentry *dir; 5762306a36Sopenharmony_ci umode_t mode = S_IFREG | 0600; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci dir = fault_create_debugfs_attr("failslab", NULL, &failslab.attr); 6062306a36Sopenharmony_ci if (IS_ERR(dir)) 6162306a36Sopenharmony_ci return PTR_ERR(dir); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci debugfs_create_bool("ignore-gfp-wait", mode, dir, 6462306a36Sopenharmony_ci &failslab.ignore_gfp_reclaim); 6562306a36Sopenharmony_ci debugfs_create_bool("cache-filter", mode, dir, 6662306a36Sopenharmony_ci &failslab.cache_filter); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cilate_initcall(failslab_debugfs_init); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ 74