diff options
author | Akinobu Mita <akinobu.mita@gmail.com> | 2006-12-08 05:39:45 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 11:29:02 -0500 |
commit | 933e312e73f8fc39652bd4d216a5393cc3a014b9 (patch) | |
tree | a2aacc2a098c3c95fe5a94fef1a2cc9751bee79b /mm | |
parent | 8a8b6502fb669c3a0638a08955442814cedc86b1 (diff) |
[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>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/page_alloc.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 18f0e044c43d..0cc8b4376e91 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/sort.h> | 40 | #include <linux/sort.h> |
41 | #include <linux/pfn.h> | 41 | #include <linux/pfn.h> |
42 | #include <linux/backing-dev.h> | 42 | #include <linux/backing-dev.h> |
43 | #include <linux/fault-inject.h> | ||
43 | 44 | ||
44 | #include <asm/tlbflush.h> | 45 | #include <asm/tlbflush.h> |
45 | #include <asm/div64.h> | 46 | #include <asm/div64.h> |
@@ -892,6 +893,89 @@ failed: | |||
892 | #define ALLOC_HIGH 0x20 /* __GFP_HIGH set */ | 893 | #define ALLOC_HIGH 0x20 /* __GFP_HIGH set */ |
893 | #define ALLOC_CPUSET 0x40 /* check for correct cpuset */ | 894 | #define ALLOC_CPUSET 0x40 /* check for correct cpuset */ |
894 | 895 | ||
896 | #ifdef CONFIG_FAIL_PAGE_ALLOC | ||
897 | |||
898 | static struct fail_page_alloc_attr { | ||
899 | struct fault_attr attr; | ||
900 | |||
901 | u32 ignore_gfp_highmem; | ||
902 | u32 ignore_gfp_wait; | ||
903 | |||
904 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
905 | |||
906 | struct dentry *ignore_gfp_highmem_file; | ||
907 | struct dentry *ignore_gfp_wait_file; | ||
908 | |||
909 | #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
910 | |||
911 | } fail_page_alloc = { | ||
912 | .attr = FAULT_ATTR_INITIALIZER, | ||
913 | }; | ||
914 | |||
915 | static int __init setup_fail_page_alloc(char *str) | ||
916 | { | ||
917 | return setup_fault_attr(&fail_page_alloc.attr, str); | ||
918 | } | ||
919 | __setup("fail_page_alloc=", setup_fail_page_alloc); | ||
920 | |||
921 | static int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order) | ||
922 | { | ||
923 | if (gfp_mask & __GFP_NOFAIL) | ||
924 | return 0; | ||
925 | if (fail_page_alloc.ignore_gfp_highmem && (gfp_mask & __GFP_HIGHMEM)) | ||
926 | return 0; | ||
927 | if (fail_page_alloc.ignore_gfp_wait && (gfp_mask & __GFP_WAIT)) | ||
928 | return 0; | ||
929 | |||
930 | return should_fail(&fail_page_alloc.attr, 1 << order); | ||
931 | } | ||
932 | |||
933 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
934 | |||
935 | static int __init fail_page_alloc_debugfs(void) | ||
936 | { | ||
937 | mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; | ||
938 | struct dentry *dir; | ||
939 | int err; | ||
940 | |||
941 | err = init_fault_attr_dentries(&fail_page_alloc.attr, | ||
942 | "fail_page_alloc"); | ||
943 | if (err) | ||
944 | return err; | ||
945 | dir = fail_page_alloc.attr.dentries.dir; | ||
946 | |||
947 | fail_page_alloc.ignore_gfp_wait_file = | ||
948 | debugfs_create_bool("ignore-gfp-wait", mode, dir, | ||
949 | &fail_page_alloc.ignore_gfp_wait); | ||
950 | |||
951 | fail_page_alloc.ignore_gfp_highmem_file = | ||
952 | debugfs_create_bool("ignore-gfp-highmem", mode, dir, | ||
953 | &fail_page_alloc.ignore_gfp_highmem); | ||
954 | |||
955 | if (!fail_page_alloc.ignore_gfp_wait_file || | ||
956 | !fail_page_alloc.ignore_gfp_highmem_file) { | ||
957 | err = -ENOMEM; | ||
958 | debugfs_remove(fail_page_alloc.ignore_gfp_wait_file); | ||
959 | debugfs_remove(fail_page_alloc.ignore_gfp_highmem_file); | ||
960 | cleanup_fault_attr_dentries(&fail_page_alloc.attr); | ||
961 | } | ||
962 | |||
963 | return err; | ||
964 | } | ||
965 | |||
966 | late_initcall(fail_page_alloc_debugfs); | ||
967 | |||
968 | #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
969 | |||
970 | #else /* CONFIG_FAIL_PAGE_ALLOC */ | ||
971 | |||
972 | static inline int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order) | ||
973 | { | ||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | #endif /* CONFIG_FAIL_PAGE_ALLOC */ | ||
978 | |||
895 | /* | 979 | /* |
896 | * Return 1 if free pages are above 'mark'. This takes into account the order | 980 | * Return 1 if free pages are above 'mark'. This takes into account the order |
897 | * of the allocation. | 981 | * of the allocation. |
@@ -1136,6 +1220,9 @@ __alloc_pages(gfp_t gfp_mask, unsigned int order, | |||
1136 | 1220 | ||
1137 | might_sleep_if(wait); | 1221 | might_sleep_if(wait); |
1138 | 1222 | ||
1223 | if (should_fail_alloc_page(gfp_mask, order)) | ||
1224 | return NULL; | ||
1225 | |||
1139 | restart: | 1226 | restart: |
1140 | z = zonelist->zones; /* the list of zones suitable for gfp_mask */ | 1227 | z = zonelist->zones; /* the list of zones suitable for gfp_mask */ |
1141 | 1228 | ||