Commit 4dc71451 authored by Aneesh Kumar K.V's avatar Aneesh Kumar K.V Committed by Linus Torvalds

mm/follow_page_mask: add support for hugepage directory entry

Architectures like ppc64 supports hugepage size that is not mapped to
any of of the page table levels.  Instead they add an alternate page
table entry format called hugepage directory (hugepd).  hugepd indicates
that the page table entry maps to a set of hugetlb pages.  Add support
for this in generic follow_page_mask code.  We already support this
format in the generic gup code.

The default implementation prints warning and returns NULL.  We will add
ppc64 support in later patches

Link: http://lkml.kernel.org/r/1494926612-23928-7-git-send-email-aneesh.kumar@linux.vnet.ibm.comSigned-off-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Cc: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Mike Kravetz <kravetz@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e2299292
...@@ -141,6 +141,9 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr); ...@@ -141,6 +141,9 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr);
int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep); int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep);
struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
int write); int write);
struct page *follow_huge_pd(struct vm_area_struct *vma,
unsigned long address, hugepd_t hpd,
int flags, int pdshift);
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 flags); pmd_t *pmd, int flags);
struct page *follow_huge_pud(struct mm_struct *mm, unsigned long address, struct page *follow_huge_pud(struct mm_struct *mm, unsigned long address,
...@@ -175,6 +178,7 @@ static inline void hugetlb_report_meminfo(struct seq_file *m) ...@@ -175,6 +178,7 @@ static inline void hugetlb_report_meminfo(struct seq_file *m)
static inline void hugetlb_show_meminfo(void) static inline void hugetlb_show_meminfo(void)
{ {
} }
#define follow_huge_pd(vma, addr, hpd, flags, pdshift) NULL
#define follow_huge_pmd(mm, addr, pmd, flags) NULL #define follow_huge_pmd(mm, addr, pmd, flags) NULL
#define follow_huge_pud(mm, addr, pud, flags) NULL #define follow_huge_pud(mm, addr, pud, flags) NULL
#define follow_huge_pgd(mm, addr, pgd, flags) NULL #define follow_huge_pgd(mm, addr, pgd, flags) NULL
......
...@@ -226,6 +226,14 @@ static struct page *follow_pmd_mask(struct vm_area_struct *vma, ...@@ -226,6 +226,14 @@ static struct page *follow_pmd_mask(struct vm_area_struct *vma,
return page; return page;
return no_page_table(vma, flags); return no_page_table(vma, flags);
} }
if (is_hugepd(__hugepd(pmd_val(*pmd)))) {
page = follow_huge_pd(vma, address,
__hugepd(pmd_val(*pmd)), flags,
PMD_SHIFT);
if (page)
return page;
return no_page_table(vma, flags);
}
if (pmd_devmap(*pmd)) { if (pmd_devmap(*pmd)) {
ptl = pmd_lock(mm, pmd); ptl = pmd_lock(mm, pmd);
page = follow_devmap_pmd(vma, address, pmd, flags); page = follow_devmap_pmd(vma, address, pmd, flags);
...@@ -292,6 +300,14 @@ static struct page *follow_pud_mask(struct vm_area_struct *vma, ...@@ -292,6 +300,14 @@ static struct page *follow_pud_mask(struct vm_area_struct *vma,
return page; return page;
return no_page_table(vma, flags); return no_page_table(vma, flags);
} }
if (is_hugepd(__hugepd(pud_val(*pud)))) {
page = follow_huge_pd(vma, address,
__hugepd(pud_val(*pud)), flags,
PUD_SHIFT);
if (page)
return page;
return no_page_table(vma, flags);
}
if (pud_devmap(*pud)) { if (pud_devmap(*pud)) {
ptl = pud_lock(mm, pud); ptl = pud_lock(mm, pud);
page = follow_devmap_pud(vma, address, pud, flags); page = follow_devmap_pud(vma, address, pud, flags);
...@@ -311,6 +327,7 @@ static struct page *follow_p4d_mask(struct vm_area_struct *vma, ...@@ -311,6 +327,7 @@ static struct page *follow_p4d_mask(struct vm_area_struct *vma,
unsigned int flags, unsigned int *page_mask) unsigned int flags, unsigned int *page_mask)
{ {
p4d_t *p4d; p4d_t *p4d;
struct page *page;
p4d = p4d_offset(pgdp, address); p4d = p4d_offset(pgdp, address);
if (p4d_none(*p4d)) if (p4d_none(*p4d))
...@@ -319,6 +336,14 @@ static struct page *follow_p4d_mask(struct vm_area_struct *vma, ...@@ -319,6 +336,14 @@ static struct page *follow_p4d_mask(struct vm_area_struct *vma,
if (unlikely(p4d_bad(*p4d))) if (unlikely(p4d_bad(*p4d)))
return no_page_table(vma, flags); return no_page_table(vma, flags);
if (is_hugepd(__hugepd(p4d_val(*p4d)))) {
page = follow_huge_pd(vma, address,
__hugepd(p4d_val(*p4d)), flags,
P4D_SHIFT);
if (page)
return page;
return no_page_table(vma, flags);
}
return follow_pud_mask(vma, address, p4d, flags, page_mask); return follow_pud_mask(vma, address, p4d, flags, page_mask);
} }
...@@ -363,6 +388,14 @@ struct page *follow_page_mask(struct vm_area_struct *vma, ...@@ -363,6 +388,14 @@ struct page *follow_page_mask(struct vm_area_struct *vma,
return page; return page;
return no_page_table(vma, flags); return no_page_table(vma, flags);
} }
if (is_hugepd(__hugepd(pgd_val(*pgd)))) {
page = follow_huge_pd(vma, address,
__hugepd(pgd_val(*pgd)), flags,
PGDIR_SHIFT);
if (page)
return page;
return no_page_table(vma, flags);
}
return follow_p4d_mask(vma, address, pgd, flags, page_mask); return follow_p4d_mask(vma, address, pgd, flags, page_mask);
} }
......
...@@ -4668,6 +4668,14 @@ follow_huge_addr(struct mm_struct *mm, unsigned long address, ...@@ -4668,6 +4668,14 @@ follow_huge_addr(struct mm_struct *mm, unsigned long address,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
struct page * __weak
follow_huge_pd(struct vm_area_struct *vma,
unsigned long address, hugepd_t hpd, int flags, int pdshift)
{
WARN(1, "hugepd follow called with no support for hugepage directory format\n");
return NULL;
}
struct page * __weak struct page * __weak
follow_huge_pmd(struct mm_struct *mm, unsigned long address, follow_huge_pmd(struct mm_struct *mm, unsigned long address,
pmd_t *pmd, int flags) pmd_t *pmd, int flags)
......
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