Commit 83467efb authored by Naoya Horiguchi's avatar Naoya Horiguchi Committed by Linus Torvalds

mm: migrate: check movability of hugepage in unmap_and_move_huge_page()

Currently hugepage migration works well only for pmd-based hugepages
(mainly due to lack of testing,) so we had better not enable migration of
other levels of hugepages until we are ready for it.

Some users of hugepage migration (mbind, move_pages, and migrate_pages) do
page table walk and check pud/pmd_huge() there, so they are safe.  But the
other users (softoffline and memory hotremove) don't do this, so without
this patch they can try to migrate unexpected types of hugepages.

To prevent this, we introduce hugepage_migration_support() as an
architecture dependent check of whether hugepage are implemented on a pmd
basis or not.  And on some architecture multiple sizes of hugepages are
available, so hugepage_migration_support() also checks hugepage size.
Signed-off-by: default avatarNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Hillf Danton <dhillf@gmail.com>
Cc: Wanpeng Li <liwanp@linux.vnet.ibm.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Hugh Dickins <hughd@google.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Rik van Riel <riel@redhat.com>
Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent c8721bbb
...@@ -56,3 +56,8 @@ int pmd_huge(pmd_t pmd) ...@@ -56,3 +56,8 @@ int pmd_huge(pmd_t pmd)
{ {
return pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT); return pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
} }
int pmd_huge_support(void)
{
return 1;
}
...@@ -54,6 +54,11 @@ int pud_huge(pud_t pud) ...@@ -54,6 +54,11 @@ int pud_huge(pud_t pud)
return !(pud_val(pud) & PUD_TABLE_BIT); return !(pud_val(pud) & PUD_TABLE_BIT);
} }
int pmd_huge_support(void)
{
return 1;
}
static __init int setup_hugepagesz(char *opt) static __init int setup_hugepagesz(char *opt)
{ {
unsigned long ps = memparse(opt, &opt); unsigned long ps = memparse(opt, &opt);
......
...@@ -114,6 +114,11 @@ int pud_huge(pud_t pud) ...@@ -114,6 +114,11 @@ int pud_huge(pud_t pud)
return 0; return 0;
} }
int pmd_huge_support(void)
{
return 0;
}
struct page * struct page *
follow_huge_pmd(struct mm_struct *mm, unsigned long address, pmd_t *pmd, int write) follow_huge_pmd(struct mm_struct *mm, unsigned long address, pmd_t *pmd, int write)
{ {
......
...@@ -110,6 +110,11 @@ int pud_huge(pud_t pud) ...@@ -110,6 +110,11 @@ int pud_huge(pud_t pud)
return 0; return 0;
} }
int pmd_huge_support(void)
{
return 1;
}
struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
pmd_t *pmd, int write) pmd_t *pmd, int write)
{ {
......
...@@ -85,6 +85,11 @@ int pud_huge(pud_t pud) ...@@ -85,6 +85,11 @@ int pud_huge(pud_t pud)
return (pud_val(pud) & _PAGE_HUGE) != 0; return (pud_val(pud) & _PAGE_HUGE) != 0;
} }
int pmd_huge_support(void)
{
return 1;
}
struct page * struct page *
follow_huge_pmd(struct mm_struct *mm, unsigned long address, follow_huge_pmd(struct mm_struct *mm, unsigned long address,
pmd_t *pmd, int write) pmd_t *pmd, int write)
......
...@@ -86,6 +86,11 @@ int pgd_huge(pgd_t pgd) ...@@ -86,6 +86,11 @@ int pgd_huge(pgd_t pgd)
*/ */
return ((pgd_val(pgd) & 0x3) != 0x0); return ((pgd_val(pgd) & 0x3) != 0x0);
} }
int pmd_huge_support(void)
{
return 1;
}
#else #else
int pmd_huge(pmd_t pmd) int pmd_huge(pmd_t pmd)
{ {
...@@ -101,6 +106,11 @@ int pgd_huge(pgd_t pgd) ...@@ -101,6 +106,11 @@ int pgd_huge(pgd_t pgd)
{ {
return 0; return 0;
} }
int pmd_huge_support(void)
{
return 0;
}
#endif #endif
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
......
...@@ -223,6 +223,11 @@ int pud_huge(pud_t pud) ...@@ -223,6 +223,11 @@ int pud_huge(pud_t pud)
return 0; return 0;
} }
int pmd_huge_support(void)
{
return 1;
}
struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
pmd_t *pmdp, int write) pmd_t *pmdp, int write)
{ {
......
...@@ -83,6 +83,11 @@ int pud_huge(pud_t pud) ...@@ -83,6 +83,11 @@ int pud_huge(pud_t pud)
return 0; return 0;
} }
int pmd_huge_support(void)
{
return 0;
}
struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
pmd_t *pmd, int write) pmd_t *pmd, int write)
{ {
......
...@@ -234,6 +234,11 @@ int pud_huge(pud_t pud) ...@@ -234,6 +234,11 @@ int pud_huge(pud_t pud)
return 0; return 0;
} }
int pmd_huge_support(void)
{
return 0;
}
struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
pmd_t *pmd, int write) pmd_t *pmd, int write)
{ {
......
...@@ -166,6 +166,11 @@ int pud_huge(pud_t pud) ...@@ -166,6 +166,11 @@ int pud_huge(pud_t pud)
return !!(pud_val(pud) & _PAGE_HUGE_PAGE); return !!(pud_val(pud) & _PAGE_HUGE_PAGE);
} }
int pmd_huge_support(void)
{
return 1;
}
struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
pmd_t *pmd, int write) pmd_t *pmd, int write)
{ {
......
...@@ -59,6 +59,10 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, ...@@ -59,6 +59,10 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,
return NULL; return NULL;
} }
int pmd_huge_support(void)
{
return 0;
}
#else #else
struct page * struct page *
...@@ -77,6 +81,10 @@ int pud_huge(pud_t pud) ...@@ -77,6 +81,10 @@ int pud_huge(pud_t pud)
return !!(pud_val(pud) & _PAGE_PSE); return !!(pud_val(pud) & _PAGE_PSE);
} }
int pmd_huge_support(void)
{
return 1;
}
#endif #endif
/* x86_64 also uses this file */ /* x86_64 also uses this file */
......
...@@ -381,6 +381,16 @@ static inline pgoff_t basepage_index(struct page *page) ...@@ -381,6 +381,16 @@ static inline pgoff_t basepage_index(struct page *page)
extern void dissolve_free_huge_pages(unsigned long start_pfn, extern void dissolve_free_huge_pages(unsigned long start_pfn,
unsigned long end_pfn); unsigned long end_pfn);
int pmd_huge_support(void);
/*
* Currently hugepage migration is enabled only for pmd-based hugepage.
* This function will be updated when hugepage migration is more widely
* supported.
*/
static inline int hugepage_migration_support(struct hstate *h)
{
return pmd_huge_support() && (huge_page_shift(h) == PMD_SHIFT);
}
#else /* CONFIG_HUGETLB_PAGE */ #else /* CONFIG_HUGETLB_PAGE */
struct hstate {}; struct hstate {};
...@@ -409,6 +419,8 @@ static inline pgoff_t basepage_index(struct page *page) ...@@ -409,6 +419,8 @@ static inline pgoff_t basepage_index(struct page *page)
return page->index; return page->index;
} }
#define dissolve_free_huge_pages(s, e) do {} while (0) #define dissolve_free_huge_pages(s, e) do {} while (0)
#define pmd_huge_support() 0
#define hugepage_migration_support(h) 0
#endif /* CONFIG_HUGETLB_PAGE */ #endif /* CONFIG_HUGETLB_PAGE */
#endif /* _LINUX_HUGETLB_H */ #endif /* _LINUX_HUGETLB_H */
...@@ -949,6 +949,16 @@ static int unmap_and_move_huge_page(new_page_t get_new_page, ...@@ -949,6 +949,16 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
struct page *new_hpage = get_new_page(hpage, private, &result); struct page *new_hpage = get_new_page(hpage, private, &result);
struct anon_vma *anon_vma = NULL; struct anon_vma *anon_vma = NULL;
/*
* Movability of hugepages depends on architectures and hugepage size.
* This check is necessary because some callers of hugepage migration
* like soft offline and memory hotremove don't walk through page
* tables or check whether the hugepage is pmd-based or not before
* kicking migration.
*/
if (!hugepage_migration_support(page_hstate(hpage)))
return -ENOSYS;
if (!new_hpage) if (!new_hpage)
return -ENOMEM; return -ENOMEM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment