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