summaryrefslogtreecommitdiffstats
path: root/mm/memory-failure.c
diff options
context:
space:
mode:
authorNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>2016-01-15 19:54:07 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-15 20:56:32 -0500
commit4e41a30c6d506c884d3da9aeb316352e70679d4b (patch)
treec3761eb80cd46078a38c14471d1216dcb859122c /mm/memory-failure.c
parentd96b339f453997f2f08c52da3f41423be48c978f (diff)
mm: hwpoison: adjust for new thp refcounting
Some mm-related BUG_ON()s could trigger from hwpoison code due to recent changes in thp refcounting rule. This patch fixes them up. In the new refcounting, we no longer use tail->_mapcount to keep tail's refcount, and thereby we can simplify get/put_hwpoison_page(). And another change is that tail's refcount is not transferred to the raw page during thp split (more precisely, in new rule we don't take refcount on tail page any more.) So when we need thp split, we have to transfer the refcount properly to the 4kB soft-offlined page before migration. thp split code goes into core code only when precheck (total_mapcount(head) == page_count(head) - 1) passes to avoid useless split, where we assume that one refcount is held by the caller of thp split and the others are taken via mapping. To meet this assumption, this patch moves thp split part in soft_offline_page() after get_any_page(). [akpm@linux-foundation.org: remove unneeded #define, per Kirill] Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memory-failure.c')
-rw-r--r--mm/memory-failure.c73
1 files changed, 21 insertions, 52 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 05e079bf9425..1b99403d76f2 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -882,15 +882,7 @@ int get_hwpoison_page(struct page *page)
882{ 882{
883 struct page *head = compound_head(page); 883 struct page *head = compound_head(page);
884 884
885 if (PageHuge(head)) 885 if (!PageHuge(head) && PageTransHuge(head)) {
886 return get_page_unless_zero(head);
887
888 /*
889 * Thp tail page has special refcounting rule (refcount of tail pages
890 * is stored in ->_mapcount,) so we can't call get_page_unless_zero()
891 * directly for tail pages.
892 */
893 if (PageTransHuge(head)) {
894 /* 886 /*
895 * Non anonymous thp exists only in allocation/free time. We 887 * Non anonymous thp exists only in allocation/free time. We
896 * can't handle such a case correctly, so let's give it up. 888 * can't handle such a case correctly, so let's give it up.
@@ -902,41 +894,12 @@ int get_hwpoison_page(struct page *page)
902 page_to_pfn(page)); 894 page_to_pfn(page));
903 return 0; 895 return 0;
904 } 896 }
905
906 if (get_page_unless_zero(head)) {
907 if (PageTail(page))
908 get_page(page);
909 return 1;
910 } else {
911 return 0;
912 }
913 } 897 }
914 898
915 return get_page_unless_zero(page); 899 return get_page_unless_zero(head);
916} 900}
917EXPORT_SYMBOL_GPL(get_hwpoison_page); 901EXPORT_SYMBOL_GPL(get_hwpoison_page);
918 902
919/**
920 * put_hwpoison_page() - Put refcount for memory error handling:
921 * @page: raw error page (hit by memory error)
922 */
923void put_hwpoison_page(struct page *page)
924{
925 struct page *head = compound_head(page);
926
927 if (PageHuge(head)) {
928 put_page(head);
929 return;
930 }
931
932 if (PageTransHuge(head))
933 if (page != head)
934 put_page(head);
935
936 put_page(page);
937}
938EXPORT_SYMBOL_GPL(put_hwpoison_page);
939
940/* 903/*
941 * Do all that is necessary to remove user space mappings. Unmap 904 * Do all that is necessary to remove user space mappings. Unmap
942 * the pages and send SIGBUS to the processes if the data was dirty. 905 * the pages and send SIGBUS to the processes if the data was dirty.
@@ -1162,6 +1125,8 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
1162 return -EBUSY; 1125 return -EBUSY;
1163 } 1126 }
1164 unlock_page(hpage); 1127 unlock_page(hpage);
1128 get_hwpoison_page(p);
1129 put_hwpoison_page(hpage);
1165 VM_BUG_ON_PAGE(!page_count(p), p); 1130 VM_BUG_ON_PAGE(!page_count(p), p);
1166 hpage = compound_head(p); 1131 hpage = compound_head(p);
1167 } 1132 }
@@ -1753,24 +1718,28 @@ int soft_offline_page(struct page *page, int flags)
1753 put_hwpoison_page(page); 1718 put_hwpoison_page(page);
1754 return -EBUSY; 1719 return -EBUSY;
1755 } 1720 }
1756 if (!PageHuge(page) && PageTransHuge(hpage)) {
1757 lock_page(page);
1758 ret = split_huge_page(hpage);
1759 unlock_page(page);
1760 if (unlikely(ret)) {
1761 pr_info("soft offline: %#lx: failed to split THP\n",
1762 pfn);
1763 if (flags & MF_COUNT_INCREASED)
1764 put_hwpoison_page(page);
1765 return -EBUSY;
1766 }
1767 }
1768 1721
1769 get_online_mems(); 1722 get_online_mems();
1770
1771 ret = get_any_page(page, pfn, flags); 1723 ret = get_any_page(page, pfn, flags);
1772 put_online_mems(); 1724 put_online_mems();
1725
1773 if (ret > 0) { /* for in-use pages */ 1726 if (ret > 0) { /* for in-use pages */
1727 if (!PageHuge(page) && PageTransHuge(hpage)) {
1728 lock_page(hpage);
1729 ret = split_huge_page(hpage);
1730 unlock_page(hpage);
1731 if (unlikely(ret || PageTransCompound(page) ||
1732 !PageAnon(page))) {
1733 pr_info("soft offline: %#lx: failed to split THP\n",
1734 pfn);
1735 if (flags & MF_COUNT_INCREASED)
1736 put_hwpoison_page(hpage);
1737 return -EBUSY;
1738 }
1739 get_hwpoison_page(page);
1740 put_hwpoison_page(hpage);
1741 }
1742
1774 if (PageHuge(page)) 1743 if (PageHuge(page))
1775 ret = soft_offline_huge_page(page, flags); 1744 ret = soft_offline_huge_page(page, flags);
1776 else 1745 else