diff options
| author | Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> | 2010-05-27 20:29:17 -0400 |
|---|---|---|
| committer | Andi Kleen <ak@linux.intel.com> | 2010-08-11 03:21:36 -0400 |
| commit | 7af446a841a264a1a9675001005b29ce01d1fc57 (patch) | |
| tree | 902fec55a889d33771f267fc6242b1de43d9d0c6 | |
| parent | 0fe6e20b9c4c53b3e97096ee73a0857f60aad43f (diff) | |
HWPOISON, hugetlb: enable error handling path for hugepage
This patch just enables handling path. Real containing and
recovering operation will be implemented in following patches.
Dependency:
"hugetlb, rmap: add reverse mapping for hugepage."
Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
| -rw-r--r-- | mm/memory-failure.c | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 620b0b461593..1ec68c80788e 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | #include <linux/page-isolation.h> | 45 | #include <linux/page-isolation.h> |
| 46 | #include <linux/suspend.h> | 46 | #include <linux/suspend.h> |
| 47 | #include <linux/slab.h> | 47 | #include <linux/slab.h> |
| 48 | #include <linux/hugetlb.h> | ||
| 48 | #include "internal.h" | 49 | #include "internal.h" |
| 49 | 50 | ||
| 50 | int sysctl_memory_failure_early_kill __read_mostly = 0; | 51 | int sysctl_memory_failure_early_kill __read_mostly = 0; |
| @@ -837,6 +838,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
| 837 | int ret; | 838 | int ret; |
| 838 | int i; | 839 | int i; |
| 839 | int kill = 1; | 840 | int kill = 1; |
| 841 | struct page *hpage = compound_head(p); | ||
| 840 | 842 | ||
| 841 | if (PageReserved(p) || PageSlab(p)) | 843 | if (PageReserved(p) || PageSlab(p)) |
| 842 | return SWAP_SUCCESS; | 844 | return SWAP_SUCCESS; |
| @@ -845,10 +847,10 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
| 845 | * This check implies we don't kill processes if their pages | 847 | * This check implies we don't kill processes if their pages |
| 846 | * are in the swap cache early. Those are always late kills. | 848 | * are in the swap cache early. Those are always late kills. |
| 847 | */ | 849 | */ |
| 848 | if (!page_mapped(p)) | 850 | if (!page_mapped(hpage)) |
| 849 | return SWAP_SUCCESS; | 851 | return SWAP_SUCCESS; |
| 850 | 852 | ||
| 851 | if (PageCompound(p) || PageKsm(p)) | 853 | if (PageKsm(p)) |
| 852 | return SWAP_FAIL; | 854 | return SWAP_FAIL; |
| 853 | 855 | ||
| 854 | if (PageSwapCache(p)) { | 856 | if (PageSwapCache(p)) { |
| @@ -863,10 +865,11 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
| 863 | * XXX: the dirty test could be racy: set_page_dirty() may not always | 865 | * XXX: the dirty test could be racy: set_page_dirty() may not always |
| 864 | * be called inside page lock (it's recommended but not enforced). | 866 | * be called inside page lock (it's recommended but not enforced). |
| 865 | */ | 867 | */ |
| 866 | mapping = page_mapping(p); | 868 | mapping = page_mapping(hpage); |
| 867 | if (!PageDirty(p) && mapping && mapping_cap_writeback_dirty(mapping)) { | 869 | if (!PageDirty(hpage) && mapping && |
| 868 | if (page_mkclean(p)) { | 870 | mapping_cap_writeback_dirty(mapping)) { |
| 869 | SetPageDirty(p); | 871 | if (page_mkclean(hpage)) { |
| 872 | SetPageDirty(hpage); | ||
| 870 | } else { | 873 | } else { |
| 871 | kill = 0; | 874 | kill = 0; |
| 872 | ttu |= TTU_IGNORE_HWPOISON; | 875 | ttu |= TTU_IGNORE_HWPOISON; |
| @@ -885,14 +888,14 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
| 885 | * there's nothing that can be done. | 888 | * there's nothing that can be done. |
| 886 | */ | 889 | */ |
| 887 | if (kill) | 890 | if (kill) |
| 888 | collect_procs(p, &tokill); | 891 | collect_procs(hpage, &tokill); |
| 889 | 892 | ||
| 890 | /* | 893 | /* |
| 891 | * try_to_unmap can fail temporarily due to races. | 894 | * try_to_unmap can fail temporarily due to races. |
| 892 | * Try a few times (RED-PEN better strategy?) | 895 | * Try a few times (RED-PEN better strategy?) |
| 893 | */ | 896 | */ |
| 894 | for (i = 0; i < N_UNMAP_TRIES; i++) { | 897 | for (i = 0; i < N_UNMAP_TRIES; i++) { |
| 895 | ret = try_to_unmap(p, ttu); | 898 | ret = try_to_unmap(hpage, ttu); |
| 896 | if (ret == SWAP_SUCCESS) | 899 | if (ret == SWAP_SUCCESS) |
| 897 | break; | 900 | break; |
| 898 | pr_debug("MCE %#lx: try_to_unmap retry needed %d\n", pfn, ret); | 901 | pr_debug("MCE %#lx: try_to_unmap retry needed %d\n", pfn, ret); |
| @@ -900,7 +903,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
| 900 | 903 | ||
| 901 | if (ret != SWAP_SUCCESS) | 904 | if (ret != SWAP_SUCCESS) |
| 902 | printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n", | 905 | printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n", |
| 903 | pfn, page_mapcount(p)); | 906 | pfn, page_mapcount(hpage)); |
| 904 | 907 | ||
| 905 | /* | 908 | /* |
| 906 | * Now that the dirty bit has been propagated to the | 909 | * Now that the dirty bit has been propagated to the |
| @@ -911,7 +914,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
| 911 | * use a more force-full uncatchable kill to prevent | 914 | * use a more force-full uncatchable kill to prevent |
| 912 | * any accesses to the poisoned memory. | 915 | * any accesses to the poisoned memory. |
| 913 | */ | 916 | */ |
| 914 | kill_procs_ao(&tokill, !!PageDirty(p), trapno, | 917 | kill_procs_ao(&tokill, !!PageDirty(hpage), trapno, |
| 915 | ret != SWAP_SUCCESS, pfn); | 918 | ret != SWAP_SUCCESS, pfn); |
| 916 | 919 | ||
| 917 | return ret; | 920 | return ret; |
| @@ -921,6 +924,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) | |||
| 921 | { | 924 | { |
| 922 | struct page_state *ps; | 925 | struct page_state *ps; |
| 923 | struct page *p; | 926 | struct page *p; |
| 927 | struct page *hpage; | ||
| 924 | int res; | 928 | int res; |
| 925 | 929 | ||
| 926 | if (!sysctl_memory_failure_recovery) | 930 | if (!sysctl_memory_failure_recovery) |
| @@ -934,6 +938,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) | |||
| 934 | } | 938 | } |
| 935 | 939 | ||
| 936 | p = pfn_to_page(pfn); | 940 | p = pfn_to_page(pfn); |
| 941 | hpage = compound_head(p); | ||
| 937 | if (TestSetPageHWPoison(p)) { | 942 | if (TestSetPageHWPoison(p)) { |
| 938 | printk(KERN_ERR "MCE %#lx: already hardware poisoned\n", pfn); | 943 | printk(KERN_ERR "MCE %#lx: already hardware poisoned\n", pfn); |
| 939 | return 0; | 944 | return 0; |
| @@ -953,7 +958,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) | |||
| 953 | * that may make page_freeze_refs()/page_unfreeze_refs() mismatch. | 958 | * that may make page_freeze_refs()/page_unfreeze_refs() mismatch. |
| 954 | */ | 959 | */ |
| 955 | if (!(flags & MF_COUNT_INCREASED) && | 960 | if (!(flags & MF_COUNT_INCREASED) && |
| 956 | !get_page_unless_zero(compound_head(p))) { | 961 | !get_page_unless_zero(hpage)) { |
| 957 | if (is_free_buddy_page(p)) { | 962 | if (is_free_buddy_page(p)) { |
| 958 | action_result(pfn, "free buddy", DELAYED); | 963 | action_result(pfn, "free buddy", DELAYED); |
| 959 | return 0; | 964 | return 0; |
| @@ -971,9 +976,9 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) | |||
| 971 | * The check (unnecessarily) ignores LRU pages being isolated and | 976 | * The check (unnecessarily) ignores LRU pages being isolated and |
| 972 | * walked by the page reclaim code, however that's not a big loss. | 977 | * walked by the page reclaim code, however that's not a big loss. |
| 973 | */ | 978 | */ |
| 974 | if (!PageLRU(p)) | 979 | if (!PageLRU(p) && !PageHuge(p)) |
| 975 | shake_page(p, 0); | 980 | shake_page(p, 0); |
| 976 | if (!PageLRU(p)) { | 981 | if (!PageLRU(p) && !PageHuge(p)) { |
| 977 | /* | 982 | /* |
| 978 | * shake_page could have turned it free. | 983 | * shake_page could have turned it free. |
| 979 | */ | 984 | */ |
| @@ -991,7 +996,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) | |||
| 991 | * It's very difficult to mess with pages currently under IO | 996 | * It's very difficult to mess with pages currently under IO |
| 992 | * and in many cases impossible, so we just avoid it here. | 997 | * and in many cases impossible, so we just avoid it here. |
| 993 | */ | 998 | */ |
| 994 | lock_page_nosync(p); | 999 | lock_page_nosync(hpage); |
| 995 | 1000 | ||
| 996 | /* | 1001 | /* |
| 997 | * unpoison always clear PG_hwpoison inside page lock | 1002 | * unpoison always clear PG_hwpoison inside page lock |
| @@ -1004,8 +1009,8 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) | |||
| 1004 | if (hwpoison_filter(p)) { | 1009 | if (hwpoison_filter(p)) { |
| 1005 | if (TestClearPageHWPoison(p)) | 1010 | if (TestClearPageHWPoison(p)) |
| 1006 | atomic_long_dec(&mce_bad_pages); | 1011 | atomic_long_dec(&mce_bad_pages); |
| 1007 | unlock_page(p); | 1012 | unlock_page(hpage); |
| 1008 | put_page(p); | 1013 | put_page(hpage); |
| 1009 | return 0; | 1014 | return 0; |
| 1010 | } | 1015 | } |
| 1011 | 1016 | ||
| @@ -1038,7 +1043,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) | |||
| 1038 | } | 1043 | } |
| 1039 | } | 1044 | } |
| 1040 | out: | 1045 | out: |
| 1041 | unlock_page(p); | 1046 | unlock_page(hpage); |
| 1042 | return res; | 1047 | return res; |
| 1043 | } | 1048 | } |
| 1044 | EXPORT_SYMBOL_GPL(__memory_failure); | 1049 | EXPORT_SYMBOL_GPL(__memory_failure); |
