summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2013-06-20 14:30:17 +0530
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-06-21 16:01:54 +1000
commitac52ae4721233150a3c30e9732a1c1f4f68e7db7 (patch)
tree3639fe8131c6553dd3bb353c32b24ca6822d23e6 /arch/powerpc/mm
parent29409997f8d06d693d82127d200eeaf48989fdd2 (diff)
powerpc: Update find_linux_pte_or_hugepte to handle transparent hugepages
Reviewed-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/hugetlbpage.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 2865077e015..49282045ee9 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -936,30 +936,50 @@ pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift
pg = pgdir + pgd_index(ea);
- if (pgd_huge(*pg)) {
+ /*
+ * we should first check for none. That takes care of a
+ * a parallel hugetlb or THP pagefault moving none entries
+ * to respective types.
+ */
+ if (pgd_none(*pg))
+ return NULL;
+ else if (pgd_huge(*pg)) {
ret_pte = (pte_t *) pg;
goto out;
} else if (is_hugepd(pg))
hpdp = (hugepd_t *)pg;
- else if (!pgd_none(*pg)) {
+ else {
pdshift = PUD_SHIFT;
pu = pud_offset(pg, ea);
- if (pud_huge(*pu)) {
+ if (pud_none(*pu))
+ return NULL;
+ else if (pud_huge(*pu)) {
ret_pte = (pte_t *) pu;
goto out;
} else if (is_hugepd(pu))
hpdp = (hugepd_t *)pu;
- else if (!pud_none(*pu)) {
+ else {
pdshift = PMD_SHIFT;
pm = pmd_offset(pu, ea);
+ /*
+ * A hugepage collapse is captured by pmd_none, because
+ * it mark the pmd none and do a hpte invalidate.
+ *
+ * A hugepage split is captured by pmd_trans_splitting
+ * because we mark the pmd trans splitting and do a
+ * hpte invalidate
+ *
+ */
+ if (pmd_none(*pm) || pmd_trans_splitting(*pm))
+ return NULL;
- if (pmd_huge(*pm)) {
+ if (pmd_huge(*pm) || pmd_large(*pm)) {
ret_pte = (pte_t *) pm;
goto out;
} else if (is_hugepd(pm))
hpdp = (hugepd_t *)pm;
- else if (!pmd_none(*pm))
+ else
return pte_offset_kernel(pm, ea);
}
}