aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPunit Agrawal <punit.agrawal@arm.com>2017-06-08 13:25:26 -0400
committerWill Deacon <will.deacon@arm.com>2017-06-12 11:04:28 -0400
commitf02ab08afbe76ee7b0b2a34a9970e7dd200d8b01 (patch)
tree03640d83e1c6c1614ef4eafcb121641299896d24
parent687644209a6e95576ea453977b26dbd6248cadda (diff)
arm64: hugetlb: Fix huge_pte_offset to return poisoned page table entries
When memory failure is enabled, a poisoned hugepage pte is marked as a swap entry. huge_pte_offset() does not return the poisoned page table entries when it encounters PUD/PMD hugepages. This behaviour of huge_pte_offset() leads to error such as below when munmap is called on poisoned hugepages. [ 344.165544] mm/pgtable-generic.c:33: bad pmd 000000083af00074. Fix huge_pte_offset() to return the poisoned pte which is then appropriately handled by the generic layer code. Signed-off-by: Punit Agrawal <punit.agrawal@arm.com> Acked-by: Steve Capper <steve.capper@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Cc: David Woods <dwoods@mellanox.com> Tested-by: Manoj Iyer <manoj.iyer@canonical.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/include/asm/pgtable.h2
-rw-r--r--arch/arm64/mm/hugetlbpage.c29
2 files changed, 11 insertions, 20 deletions
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index c213fdbd056c..6eae342ced6b 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -441,7 +441,7 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
441 441
442#define pud_none(pud) (!pud_val(pud)) 442#define pud_none(pud) (!pud_val(pud))
443#define pud_bad(pud) (!(pud_val(pud) & PUD_TABLE_BIT)) 443#define pud_bad(pud) (!(pud_val(pud) & PUD_TABLE_BIT))
444#define pud_present(pud) (pud_val(pud)) 444#define pud_present(pud) pte_present(pud_pte(pud))
445 445
446static inline void set_pud(pud_t *pudp, pud_t pud) 446static inline void set_pud(pud_t *pudp, pud_t pud)
447{ 447{
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 7514a000e361..69b8200b1cfd 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -136,36 +136,27 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
136{ 136{
137 pgd_t *pgd; 137 pgd_t *pgd;
138 pud_t *pud; 138 pud_t *pud;
139 pmd_t *pmd = NULL; 139 pmd_t *pmd;
140 pte_t *pte = NULL;
141 140
142 pgd = pgd_offset(mm, addr); 141 pgd = pgd_offset(mm, addr);
143 pr_debug("%s: addr:0x%lx pgd:%p\n", __func__, addr, pgd); 142 pr_debug("%s: addr:0x%lx pgd:%p\n", __func__, addr, pgd);
144 if (!pgd_present(*pgd)) 143 if (!pgd_present(*pgd))
145 return NULL; 144 return NULL;
145
146 pud = pud_offset(pgd, addr); 146 pud = pud_offset(pgd, addr);
147 if (!pud_present(*pud)) 147 if (pud_none(*pud))
148 return NULL; 148 return NULL;
149 149 /* swap or huge page */
150 if (pud_huge(*pud)) 150 if (!pud_present(*pud) || pud_huge(*pud))
151 return (pte_t *)pud; 151 return (pte_t *)pud;
152 /* table; check the next level */
153
152 pmd = pmd_offset(pud, addr); 154 pmd = pmd_offset(pud, addr);
153 if (!pmd_present(*pmd)) 155 if (pmd_none(*pmd))
154 return NULL; 156 return NULL;
155 157 if (!pmd_present(*pmd) || pmd_huge(*pmd))
156 if (pte_cont(pmd_pte(*pmd))) {
157 pmd = pmd_offset(
158 pud, (addr & CONT_PMD_MASK));
159 return (pte_t *)pmd;
160 }
161 if (pmd_huge(*pmd))
162 return (pte_t *)pmd; 158 return (pte_t *)pmd;
163 pte = pte_offset_kernel(pmd, addr); 159
164 if (pte_present(*pte) && pte_cont(*pte)) {
165 pte = pte_offset_kernel(
166 pmd, (addr & CONT_PTE_MASK));
167 return pte;
168 }
169 return NULL; 160 return NULL;
170} 161}
171 162