diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memory-failure.c | 21 |
1 files changed, 11 insertions, 10 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 7e3601ce51c6..3b4120e38d48 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c | |||
@@ -854,14 +854,14 @@ static int page_action(struct page_state *ps, struct page *p, | |||
854 | * the pages and send SIGBUS to the processes if the data was dirty. | 854 | * the pages and send SIGBUS to the processes if the data was dirty. |
855 | */ | 855 | */ |
856 | static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | 856 | static int hwpoison_user_mappings(struct page *p, unsigned long pfn, |
857 | int trapno, int flags) | 857 | int trapno, int flags, struct page **hpagep) |
858 | { | 858 | { |
859 | enum ttu_flags ttu = TTU_UNMAP | TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS; | 859 | enum ttu_flags ttu = TTU_UNMAP | TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS; |
860 | struct address_space *mapping; | 860 | struct address_space *mapping; |
861 | LIST_HEAD(tokill); | 861 | LIST_HEAD(tokill); |
862 | int ret; | 862 | int ret; |
863 | int kill = 1, forcekill; | 863 | int kill = 1, forcekill; |
864 | struct page *hpage = compound_head(p); | 864 | struct page *hpage = *hpagep; |
865 | struct page *ppage; | 865 | struct page *ppage; |
866 | 866 | ||
867 | if (PageReserved(p) || PageSlab(p)) | 867 | if (PageReserved(p) || PageSlab(p)) |
@@ -940,11 +940,14 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
940 | * We pinned the head page for hwpoison handling, | 940 | * We pinned the head page for hwpoison handling, |
941 | * now we split the thp and we are interested in | 941 | * now we split the thp and we are interested in |
942 | * the hwpoisoned raw page, so move the refcount | 942 | * the hwpoisoned raw page, so move the refcount |
943 | * to it. | 943 | * to it. Similarly, page lock is shifted. |
944 | */ | 944 | */ |
945 | if (hpage != p) { | 945 | if (hpage != p) { |
946 | put_page(hpage); | 946 | put_page(hpage); |
947 | get_page(p); | 947 | get_page(p); |
948 | lock_page(p); | ||
949 | unlock_page(hpage); | ||
950 | *hpagep = p; | ||
948 | } | 951 | } |
949 | /* THP is split, so ppage should be the real poisoned page. */ | 952 | /* THP is split, so ppage should be the real poisoned page. */ |
950 | ppage = p; | 953 | ppage = p; |
@@ -962,17 +965,11 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
962 | if (kill) | 965 | if (kill) |
963 | collect_procs(ppage, &tokill); | 966 | collect_procs(ppage, &tokill); |
964 | 967 | ||
965 | if (hpage != ppage) | ||
966 | lock_page(ppage); | ||
967 | |||
968 | ret = try_to_unmap(ppage, ttu); | 968 | ret = try_to_unmap(ppage, ttu); |
969 | if (ret != SWAP_SUCCESS) | 969 | if (ret != SWAP_SUCCESS) |
970 | printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n", | 970 | printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n", |
971 | pfn, page_mapcount(ppage)); | 971 | pfn, page_mapcount(ppage)); |
972 | 972 | ||
973 | if (hpage != ppage) | ||
974 | unlock_page(ppage); | ||
975 | |||
976 | /* | 973 | /* |
977 | * Now that the dirty bit has been propagated to the | 974 | * Now that the dirty bit has been propagated to the |
978 | * struct page and all unmaps done we can decide if | 975 | * struct page and all unmaps done we can decide if |
@@ -1189,8 +1186,12 @@ int memory_failure(unsigned long pfn, int trapno, int flags) | |||
1189 | /* | 1186 | /* |
1190 | * Now take care of user space mappings. | 1187 | * Now take care of user space mappings. |
1191 | * Abort on fail: __delete_from_page_cache() assumes unmapped page. | 1188 | * Abort on fail: __delete_from_page_cache() assumes unmapped page. |
1189 | * | ||
1190 | * When the raw error page is thp tail page, hpage points to the raw | ||
1191 | * page after thp split. | ||
1192 | */ | 1192 | */ |
1193 | if (hwpoison_user_mappings(p, pfn, trapno, flags) != SWAP_SUCCESS) { | 1193 | if (hwpoison_user_mappings(p, pfn, trapno, flags, &hpage) |
1194 | != SWAP_SUCCESS) { | ||
1194 | printk(KERN_ERR "MCE %#lx: cannot unmap page, give up\n", pfn); | 1195 | printk(KERN_ERR "MCE %#lx: cannot unmap page, give up\n", pfn); |
1195 | res = -EBUSY; | 1196 | res = -EBUSY; |
1196 | goto out; | 1197 | goto out; |