diff options
-rw-r--r-- | lib/Kconfig.debug | 7 | ||||
-rw-r--r-- | mm/page_alloc.c | 87 |
2 files changed, 94 insertions, 0 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c7f567a57d7d..c66b7b400c9f 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -424,6 +424,13 @@ config FAILSLAB | |||
424 | help | 424 | help |
425 | This option provides fault-injection capabilitiy for kmalloc. | 425 | This option provides fault-injection capabilitiy for kmalloc. |
426 | 426 | ||
427 | config FAIL_PAGE_ALLOC | ||
428 | bool "Fault-injection capabilitiy for alloc_pages()" | ||
429 | depends on DEBUG_KERNEL | ||
430 | select FAULT_INJECTION | ||
431 | help | ||
432 | This option provides fault-injection capabilitiy for alloc_pages(). | ||
433 | |||
427 | config FAULT_INJECTION_DEBUG_FS | 434 | config FAULT_INJECTION_DEBUG_FS |
428 | bool "Debugfs entries for fault-injection capabilities" | 435 | bool "Debugfs entries for fault-injection capabilities" |
429 | depends on FAULT_INJECTION && SYSFS | 436 | depends on FAULT_INJECTION && SYSFS |
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 | ||