diff options
author | Dave Hansen <dave.hansen@linux.intel.com> | 2013-11-21 17:31:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-21 19:42:27 -0500 |
commit | 30b0a105d9f7141e4cbf72ae5511832457d89788 (patch) | |
tree | bbd52a86e93e43e7e5a2bfd234bffef9b796e055 /include/linux/hugetlb.h | |
parent | c11230f44b3c3e055e4e7cd572fc1c4a22c6f4a9 (diff) |
mm: thp: give transparent hugepage code a separate copy_page
Right now, the migration code in migrate_page_copy() uses copy_huge_page()
for hugetlbfs and thp pages:
if (PageHuge(page) || PageTransHuge(page))
copy_huge_page(newpage, page);
So, yay for code reuse. But:
void copy_huge_page(struct page *dst, struct page *src)
{
struct hstate *h = page_hstate(src);
and a non-hugetlbfs page has no page_hstate(). This works 99% of the
time because page_hstate() determines the hstate from the page order
alone. Since the page order of a THP page matches the default hugetlbfs
page order, it works.
But, if you change the default huge page size on the boot command-line
(say default_hugepagesz=1G), then we might not even *have* a 2MB hstate
so page_hstate() returns null and copy_huge_page() oopses pretty fast
since copy_huge_page() dereferences the hstate:
void copy_huge_page(struct page *dst, struct page *src)
{
struct hstate *h = page_hstate(src);
if (unlikely(pages_per_huge_page(h) > MAX_ORDER_NR_PAGES)) {
...
Mel noticed that the migration code is really the only user of these
functions. This moves all the copy code over to migrate.c and makes
copy_huge_page() work for THP by checking for it explicitly.
I believe the bug was introduced in commit b32967ff101a ("mm: numa: Add
THP migration for the NUMA working set scanning fault case")
[akpm@linux-foundation.org: fix coding-style and comment text, per Naoya Horiguchi]
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Acked-by: Mel Gorman <mgorman@suse.de>
Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Hillf Danton <dhillf@gmail.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Tested-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux/hugetlb.h')
-rw-r--r-- | include/linux/hugetlb.h | 4 |
1 files changed, 0 insertions, 4 deletions
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index acd2010328f3..85e0c58bdfdf 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h | |||
@@ -69,7 +69,6 @@ int dequeue_hwpoisoned_huge_page(struct page *page); | |||
69 | bool isolate_huge_page(struct page *page, struct list_head *list); | 69 | bool isolate_huge_page(struct page *page, struct list_head *list); |
70 | void putback_active_hugepage(struct page *page); | 70 | void putback_active_hugepage(struct page *page); |
71 | bool is_hugepage_active(struct page *page); | 71 | bool is_hugepage_active(struct page *page); |
72 | void copy_huge_page(struct page *dst, struct page *src); | ||
73 | 72 | ||
74 | #ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE | 73 | #ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE |
75 | pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud); | 74 | pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud); |
@@ -140,9 +139,6 @@ static inline int dequeue_hwpoisoned_huge_page(struct page *page) | |||
140 | #define isolate_huge_page(p, l) false | 139 | #define isolate_huge_page(p, l) false |
141 | #define putback_active_hugepage(p) do {} while (0) | 140 | #define putback_active_hugepage(p) do {} while (0) |
142 | #define is_hugepage_active(x) false | 141 | #define is_hugepage_active(x) false |
143 | static inline void copy_huge_page(struct page *dst, struct page *src) | ||
144 | { | ||
145 | } | ||
146 | 142 | ||
147 | static inline unsigned long hugetlb_change_protection(struct vm_area_struct *vma, | 143 | static inline unsigned long hugetlb_change_protection(struct vm_area_struct *vma, |
148 | unsigned long address, unsigned long end, pgprot_t newprot) | 144 | unsigned long address, unsigned long end, pgprot_t newprot) |