summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/pgtable.h19
-rw-r--r--arch/arm64/mm/fault.c30
-rw-r--r--arch/arm64/mm/hugetlbpage.c6
3 files changed, 42 insertions, 13 deletions
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index b1a96a8f2b17..53e39d2182f5 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -1248,9 +1248,18 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
return pte_pmd(pte_modify(pmd_pte(pmd), newprot));
}
-extern int __ptep_set_access_flags(struct vm_area_struct *vma,
- unsigned long address, pte_t *ptep,
- pte_t entry, int dirty);
+extern int __ptep_set_access_flags_anysz(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep,
+ pte_t entry, int dirty,
+ unsigned long pgsize);
+
+static inline int __ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep,
+ pte_t entry, int dirty)
+{
+ return __ptep_set_access_flags_anysz(vma, address, ptep, entry, dirty,
+ PAGE_SIZE);
+}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
@@ -1258,8 +1267,8 @@ static inline int pmdp_set_access_flags(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp,
pmd_t entry, int dirty)
{
- return __ptep_set_access_flags(vma, address, (pte_t *)pmdp,
- pmd_pte(entry), dirty);
+ return __ptep_set_access_flags_anysz(vma, address, (pte_t *)pmdp,
+ pmd_pte(entry), dirty, PMD_SIZE);
}
#endif
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index f91aa686f142..920a8b244d59 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -204,12 +204,13 @@ static void show_pte(unsigned long addr)
*
* Returns whether or not the PTE actually changed.
*/
-int __ptep_set_access_flags(struct vm_area_struct *vma,
- unsigned long address, pte_t *ptep,
- pte_t entry, int dirty)
+int __ptep_set_access_flags_anysz(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep,
+ pte_t entry, int dirty, unsigned long pgsize)
{
pteval_t old_pteval, pteval;
pte_t pte = __ptep_get(ptep);
+ int level;
if (pte_same(pte, entry))
return 0;
@@ -238,8 +239,27 @@ int __ptep_set_access_flags(struct vm_area_struct *vma,
* may still cause page faults and be invalidated via
* flush_tlb_fix_spurious_fault().
*/
- if (dirty)
- __flush_tlb_page(vma, address, TLBF_NOBROADCAST);
+ if (dirty) {
+ switch (pgsize) {
+ case PAGE_SIZE:
+ level = 3;
+ break;
+ case PMD_SIZE:
+ level = 2;
+ break;
+#ifndef __PAGETABLE_PMD_FOLDED
+ case PUD_SIZE:
+ level = 1;
+ break;
+#endif
+ default:
+ level = TLBI_TTL_UNKNOWN;
+ WARN_ON(1);
+ }
+
+ __flush_tlb_range(vma, address, address + pgsize, pgsize, level,
+ TLBF_NOWALKCACHE | TLBF_NOBROADCAST);
+ }
return 1;
}
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 0b7ccd0cbb9e..30772a909aea 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -427,11 +427,11 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
pte_t orig_pte;
VM_WARN_ON(!pte_present(pte));
+ ncontig = num_contig_ptes(huge_page_size(hstate_vma(vma)), &pgsize);
if (!pte_cont(pte))
- return __ptep_set_access_flags(vma, addr, ptep, pte, dirty);
-
- ncontig = num_contig_ptes(huge_page_size(hstate_vma(vma)), &pgsize);
+ return __ptep_set_access_flags_anysz(vma, addr, ptep, pte,
+ dirty, pgsize);
if (!__cont_access_flags_changed(ptep, pte, ncontig))
return 0;