162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/fault-inject.h>
362306a36Sopenharmony_ci#include <linux/mm.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_cistatic struct {
662306a36Sopenharmony_ci	struct fault_attr attr;
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci	bool ignore_gfp_highmem;
962306a36Sopenharmony_ci	bool ignore_gfp_reclaim;
1062306a36Sopenharmony_ci	u32 min_order;
1162306a36Sopenharmony_ci} fail_page_alloc = {
1262306a36Sopenharmony_ci	.attr = FAULT_ATTR_INITIALIZER,
1362306a36Sopenharmony_ci	.ignore_gfp_reclaim = true,
1462306a36Sopenharmony_ci	.ignore_gfp_highmem = true,
1562306a36Sopenharmony_ci	.min_order = 1,
1662306a36Sopenharmony_ci};
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic int __init setup_fail_page_alloc(char *str)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	return setup_fault_attr(&fail_page_alloc.attr, str);
2162306a36Sopenharmony_ci}
2262306a36Sopenharmony_ci__setup("fail_page_alloc=", setup_fail_page_alloc);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cibool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	int flags = 0;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (order < fail_page_alloc.min_order)
2962306a36Sopenharmony_ci		return false;
3062306a36Sopenharmony_ci	if (gfp_mask & __GFP_NOFAIL)
3162306a36Sopenharmony_ci		return false;
3262306a36Sopenharmony_ci	if (fail_page_alloc.ignore_gfp_highmem && (gfp_mask & __GFP_HIGHMEM))
3362306a36Sopenharmony_ci		return false;
3462306a36Sopenharmony_ci	if (fail_page_alloc.ignore_gfp_reclaim &&
3562306a36Sopenharmony_ci			(gfp_mask & __GFP_DIRECT_RECLAIM))
3662306a36Sopenharmony_ci		return false;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/* See comment in __should_failslab() */
3962306a36Sopenharmony_ci	if (gfp_mask & __GFP_NOWARN)
4062306a36Sopenharmony_ci		flags |= FAULT_NOWARN;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return should_fail_ex(&fail_page_alloc.attr, 1 << order, flags);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int __init fail_page_alloc_debugfs(void)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	umode_t mode = S_IFREG | 0600;
5062306a36Sopenharmony_ci	struct dentry *dir;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	dir = fault_create_debugfs_attr("fail_page_alloc", NULL,
5362306a36Sopenharmony_ci					&fail_page_alloc.attr);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	debugfs_create_bool("ignore-gfp-wait", mode, dir,
5662306a36Sopenharmony_ci			    &fail_page_alloc.ignore_gfp_reclaim);
5762306a36Sopenharmony_ci	debugfs_create_bool("ignore-gfp-highmem", mode, dir,
5862306a36Sopenharmony_ci			    &fail_page_alloc.ignore_gfp_highmem);
5962306a36Sopenharmony_ci	debugfs_create_u32("min-order", mode, dir, &fail_page_alloc.min_order);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return 0;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cilate_initcall(fail_page_alloc_debugfs);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
67