[PATCH] fault-injection capability for alloc_pages()
This patch provides fault-injection capability for alloc_pages() Boot option: fail_page_alloc=<interval>,<probability>,<space>,<times> <interval> -- specifies the interval of failures. <probability> -- specifies how often it should fail in percent. <space> -- specifies the size of free space where memory can be allocated safely in pages. <times> -- specifies how many times failures may happen at most. Debugfs: /debug/fail_page_alloc/interval /debug/fail_page_alloc/probability /debug/fail_page_alloc/specifies /debug/fail_page_alloc/times /debug/fail_page_alloc/ignore-gfp-highmem /debug/fail_page_alloc/ignore-gfp-wait Example: fail_page_alloc=10,100,0,-1 The page allocation (alloc_pages(), ...) fails once per 10 times. Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
8a8b6502fb
commit
933e312e73
2 changed files with 94 additions and 0 deletions
|
@ -424,6 +424,13 @@ config FAILSLAB
|
||||||
help
|
help
|
||||||
This option provides fault-injection capabilitiy for kmalloc.
|
This option provides fault-injection capabilitiy for kmalloc.
|
||||||
|
|
||||||
|
config FAIL_PAGE_ALLOC
|
||||||
|
bool "Fault-injection capabilitiy for alloc_pages()"
|
||||||
|
depends on DEBUG_KERNEL
|
||||||
|
select FAULT_INJECTION
|
||||||
|
help
|
||||||
|
This option provides fault-injection capabilitiy for alloc_pages().
|
||||||
|
|
||||||
config FAULT_INJECTION_DEBUG_FS
|
config FAULT_INJECTION_DEBUG_FS
|
||||||
bool "Debugfs entries for fault-injection capabilities"
|
bool "Debugfs entries for fault-injection capabilities"
|
||||||
depends on FAULT_INJECTION && SYSFS
|
depends on FAULT_INJECTION && SYSFS
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <linux/sort.h>
|
#include <linux/sort.h>
|
||||||
#include <linux/pfn.h>
|
#include <linux/pfn.h>
|
||||||
#include <linux/backing-dev.h>
|
#include <linux/backing-dev.h>
|
||||||
|
#include <linux/fault-inject.h>
|
||||||
|
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
#include <asm/div64.h>
|
#include <asm/div64.h>
|
||||||
|
@ -892,6 +893,89 @@ static struct page *buffered_rmqueue(struct zonelist *zonelist,
|
||||||
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
|
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
|
||||||
#define ALLOC_CPUSET 0x40 /* check for correct cpuset */
|
#define ALLOC_CPUSET 0x40 /* check for correct cpuset */
|
||||||
|
|
||||||
|
#ifdef CONFIG_FAIL_PAGE_ALLOC
|
||||||
|
|
||||||
|
static struct fail_page_alloc_attr {
|
||||||
|
struct fault_attr attr;
|
||||||
|
|
||||||
|
u32 ignore_gfp_highmem;
|
||||||
|
u32 ignore_gfp_wait;
|
||||||
|
|
||||||
|
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
|
||||||
|
|
||||||
|
struct dentry *ignore_gfp_highmem_file;
|
||||||
|
struct dentry *ignore_gfp_wait_file;
|
||||||
|
|
||||||
|
#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
|
||||||
|
|
||||||
|
} fail_page_alloc = {
|
||||||
|
.attr = FAULT_ATTR_INITIALIZER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init setup_fail_page_alloc(char *str)
|
||||||
|
{
|
||||||
|
return setup_fault_attr(&fail_page_alloc.attr, str);
|
||||||
|
}
|
||||||
|
__setup("fail_page_alloc=", setup_fail_page_alloc);
|
||||||
|
|
||||||
|
static int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
|
||||||
|
{
|
||||||
|
if (gfp_mask & __GFP_NOFAIL)
|
||||||
|
return 0;
|
||||||
|
if (fail_page_alloc.ignore_gfp_highmem && (gfp_mask & __GFP_HIGHMEM))
|
||||||
|
return 0;
|
||||||
|
if (fail_page_alloc.ignore_gfp_wait && (gfp_mask & __GFP_WAIT))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return should_fail(&fail_page_alloc.attr, 1 << order);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
|
||||||
|
|
||||||
|
static int __init fail_page_alloc_debugfs(void)
|
||||||
|
{
|
||||||
|
mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
|
||||||
|
struct dentry *dir;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = init_fault_attr_dentries(&fail_page_alloc.attr,
|
||||||
|
"fail_page_alloc");
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
dir = fail_page_alloc.attr.dentries.dir;
|
||||||
|
|
||||||
|
fail_page_alloc.ignore_gfp_wait_file =
|
||||||
|
debugfs_create_bool("ignore-gfp-wait", mode, dir,
|
||||||
|
&fail_page_alloc.ignore_gfp_wait);
|
||||||
|
|
||||||
|
fail_page_alloc.ignore_gfp_highmem_file =
|
||||||
|
debugfs_create_bool("ignore-gfp-highmem", mode, dir,
|
||||||
|
&fail_page_alloc.ignore_gfp_highmem);
|
||||||
|
|
||||||
|
if (!fail_page_alloc.ignore_gfp_wait_file ||
|
||||||
|
!fail_page_alloc.ignore_gfp_highmem_file) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
debugfs_remove(fail_page_alloc.ignore_gfp_wait_file);
|
||||||
|
debugfs_remove(fail_page_alloc.ignore_gfp_highmem_file);
|
||||||
|
cleanup_fault_attr_dentries(&fail_page_alloc.attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
late_initcall(fail_page_alloc_debugfs);
|
||||||
|
|
||||||
|
#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
|
||||||
|
|
||||||
|
#else /* CONFIG_FAIL_PAGE_ALLOC */
|
||||||
|
|
||||||
|
static inline int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_FAIL_PAGE_ALLOC */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return 1 if free pages are above 'mark'. This takes into account the order
|
* Return 1 if free pages are above 'mark'. This takes into account the order
|
||||||
* of the allocation.
|
* of the allocation.
|
||||||
|
@ -1136,6 +1220,9 @@ __alloc_pages(gfp_t gfp_mask, unsigned int order,
|
||||||
|
|
||||||
might_sleep_if(wait);
|
might_sleep_if(wait);
|
||||||
|
|
||||||
|
if (should_fail_alloc_page(gfp_mask, order))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
z = zonelist->zones; /* the list of zones suitable for gfp_mask */
|
z = zonelist->zones; /* the list of zones suitable for gfp_mask */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue