Skip to content

Commit

Permalink
[PATCH] fault-injection capability for alloc_pages()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mita authored and Linus Torvalds committed Dec 8, 2006
1 parent 8a8b650 commit 933e312
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
7 changes: 7 additions & 0 deletions lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,13 @@ config FAILSLAB
help
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
bool "Debugfs entries for fault-injection capabilities"
depends on FAULT_INJECTION && SYSFS
Expand Down
87 changes: 87 additions & 0 deletions mm/page_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <linux/sort.h>
#include <linux/pfn.h>
#include <linux/backing-dev.h>
#include <linux/fault-inject.h>

#include <asm/tlbflush.h>
#include <asm/div64.h>
Expand Down Expand Up @@ -892,6 +893,89 @@ static struct page *buffered_rmqueue(struct zonelist *zonelist,
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
#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
* of the allocation.
Expand Down Expand Up @@ -1136,6 +1220,9 @@ __alloc_pages(gfp_t gfp_mask, unsigned int order,

might_sleep_if(wait);

if (should_fail_alloc_page(gfp_mask, order))
return NULL;

restart:
z = zonelist->zones; /* the list of zones suitable for gfp_mask */

Expand Down

0 comments on commit 933e312

Please sign in to comment.