diff options
Diffstat (limited to 'mm/memory-failure.c')
-rw-r--r-- | mm/memory-failure.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index b7c171602ba1..fabe55046c1d 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c | |||
@@ -938,6 +938,16 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, | |||
938 | BUG_ON(!PageHWPoison(p)); | 938 | BUG_ON(!PageHWPoison(p)); |
939 | return SWAP_FAIL; | 939 | return SWAP_FAIL; |
940 | } | 940 | } |
941 | /* | ||
942 | * We pinned the head page for hwpoison handling, | ||
943 | * now we split the thp and we are interested in | ||
944 | * the hwpoisoned raw page, so move the refcount | ||
945 | * to it. | ||
946 | */ | ||
947 | if (hpage != p) { | ||
948 | put_page(hpage); | ||
949 | get_page(p); | ||
950 | } | ||
941 | /* THP is split, so ppage should be the real poisoned page. */ | 951 | /* THP is split, so ppage should be the real poisoned page. */ |
942 | ppage = p; | 952 | ppage = p; |
943 | } | 953 | } |
@@ -1505,10 +1515,16 @@ static int soft_offline_huge_page(struct page *page, int flags) | |||
1505 | if (ret > 0) | 1515 | if (ret > 0) |
1506 | ret = -EIO; | 1516 | ret = -EIO; |
1507 | } else { | 1517 | } else { |
1508 | set_page_hwpoison_huge_page(hpage); | 1518 | /* overcommit hugetlb page will be freed to buddy */ |
1509 | dequeue_hwpoisoned_huge_page(hpage); | 1519 | if (PageHuge(page)) { |
1510 | atomic_long_add(1 << compound_order(hpage), | 1520 | set_page_hwpoison_huge_page(hpage); |
1511 | &num_poisoned_pages); | 1521 | dequeue_hwpoisoned_huge_page(hpage); |
1522 | atomic_long_add(1 << compound_order(hpage), | ||
1523 | &num_poisoned_pages); | ||
1524 | } else { | ||
1525 | SetPageHWPoison(page); | ||
1526 | atomic_long_inc(&num_poisoned_pages); | ||
1527 | } | ||
1512 | } | 1528 | } |
1513 | return ret; | 1529 | return ret; |
1514 | } | 1530 | } |