ioremap: Update pgtable free interfaces with addr
authorChintan Pandya <cpandya@codeaurora.org>
Wed, 27 Jun 2018 14:13:47 +0000 (08:13 -0600)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 4 Jul 2018 19:37:08 +0000 (21:37 +0200)
The following kernel panic was observed on ARM64 platform due to a stale
TLB entry.

 1. ioremap with 4K size, a valid pte page table is set.
 2. iounmap it, its pte entry is set to 0.
 3. ioremap the same address with 2M size, update its pmd entry with
    a new value.
 4. CPU may hit an exception because the old pmd entry is still in TLB,
    which leads to a kernel panic.

Commit b6bdb7517c3d ("mm/vmalloc: add interfaces to free unmapped page
table") has addressed this panic by falling to pte mappings in the above
case on ARM64.

To support pmd mappings in all cases, TLB purge needs to be performed
in this case on ARM64.

Add a new arg, 'addr', to pud_free_pmd_page() and pmd_free_pte_page()
so that TLB purge can be added later in seprate patches.

[toshi.kani@hpe.com: merge changes, rewrite patch description]
Fixes: 28ee90fe6048 ("x86/mm: implement free pmd/pte page interfaces")
Signed-off-by: Chintan Pandya <cpandya@codeaurora.org>
Signed-off-by: Toshi Kani <toshi.kani@hpe.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: mhocko@suse.com
Cc: akpm@linux-foundation.org
Cc: hpa@zytor.com
Cc: linux-mm@kvack.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: Will Deacon <will.deacon@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: stable@vger.kernel.org
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: <stable@vger.kernel.org>
Link: https://lkml.kernel.org/r/20180627141348.21777-3-toshi.kani@hpe.com
arch/arm64/mm/mmu.c
arch/x86/mm/pgtable.c
include/asm-generic/pgtable.h
lib/ioremap.c

index 493ff75670ffd98a1dc344a133f0f31a634f93ff..8ae5d7ae4af344967f3cfeb711f2eade43dcf76a 100644 (file)
@@ -977,12 +977,12 @@ int pmd_clear_huge(pmd_t *pmdp)
        return 1;
 }
 
-int pud_free_pmd_page(pud_t *pud)
+int pud_free_pmd_page(pud_t *pud, unsigned long addr)
 {
        return pud_none(*pud);
 }
 
-int pmd_free_pte_page(pmd_t *pmd)
+int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
 {
        return pmd_none(*pmd);
 }
index 1aeb7a5dbce51822400bf088bedf8969e854225b..fbd14e5067581eb7cdeb3a9b2ffbf4b5ecf38d91 100644 (file)
@@ -723,11 +723,12 @@ int pmd_clear_huge(pmd_t *pmd)
 /**
  * pud_free_pmd_page - Clear pud entry and free pmd page.
  * @pud: Pointer to a PUD.
+ * @addr: Virtual address associated with pud.
  *
  * Context: The pud range has been unmaped and TLB purged.
  * Return: 1 if clearing the entry succeeded. 0 otherwise.
  */
-int pud_free_pmd_page(pud_t *pud)
+int pud_free_pmd_page(pud_t *pud, unsigned long addr)
 {
        pmd_t *pmd;
        int i;
@@ -738,7 +739,7 @@ int pud_free_pmd_page(pud_t *pud)
        pmd = (pmd_t *)pud_page_vaddr(*pud);
 
        for (i = 0; i < PTRS_PER_PMD; i++)
-               if (!pmd_free_pte_page(&pmd[i]))
+               if (!pmd_free_pte_page(&pmd[i], addr + (i * PMD_SIZE)))
                        return 0;
 
        pud_clear(pud);
@@ -750,11 +751,12 @@ int pud_free_pmd_page(pud_t *pud)
 /**
  * pmd_free_pte_page - Clear pmd entry and free pte page.
  * @pmd: Pointer to a PMD.
+ * @addr: Virtual address associated with pmd.
  *
  * Context: The pmd range has been unmaped and TLB purged.
  * Return: 1 if clearing the entry succeeded. 0 otherwise.
  */
-int pmd_free_pte_page(pmd_t *pmd)
+int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
 {
        pte_t *pte;
 
@@ -770,7 +772,7 @@ int pmd_free_pte_page(pmd_t *pmd)
 
 #else /* !CONFIG_X86_64 */
 
-int pud_free_pmd_page(pud_t *pud)
+int pud_free_pmd_page(pud_t *pud, unsigned long addr)
 {
        return pud_none(*pud);
 }
@@ -779,7 +781,7 @@ int pud_free_pmd_page(pud_t *pud)
  * Disable free page handling on x86-PAE. This assures that ioremap()
  * does not update sync'd pmd entries. See vmalloc_sync_one().
  */
-int pmd_free_pte_page(pmd_t *pmd)
+int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
 {
        return pmd_none(*pmd);
 }
index f59639afaa3908dbcaa06cec9defc8837cba09ee..b081794ba135730fb55aebdb4a709b9c9ea1f010 100644 (file)
@@ -1019,8 +1019,8 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot);
 int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot);
 int pud_clear_huge(pud_t *pud);
 int pmd_clear_huge(pmd_t *pmd);
-int pud_free_pmd_page(pud_t *pud);
-int pmd_free_pte_page(pmd_t *pmd);
+int pud_free_pmd_page(pud_t *pud, unsigned long addr);
+int pmd_free_pte_page(pmd_t *pmd, unsigned long addr);
 #else  /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
 static inline int p4d_set_huge(p4d_t *p4d, phys_addr_t addr, pgprot_t prot)
 {
@@ -1046,11 +1046,11 @@ static inline int pmd_clear_huge(pmd_t *pmd)
 {
        return 0;
 }
-static inline int pud_free_pmd_page(pud_t *pud)
+static inline int pud_free_pmd_page(pud_t *pud, unsigned long addr)
 {
        return 0;
 }
-static inline int pmd_free_pte_page(pmd_t *pmd)
+static inline int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
 {
        return 0;
 }
index 54e5bbaa3200317534926e65982dcd3cbab71492..517f5853ffed1726a462543f902450ddb7f9a9b4 100644 (file)
@@ -92,7 +92,7 @@ static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
                if (ioremap_pmd_enabled() &&
                    ((next - addr) == PMD_SIZE) &&
                    IS_ALIGNED(phys_addr + addr, PMD_SIZE) &&
-                   pmd_free_pte_page(pmd)) {
+                   pmd_free_pte_page(pmd, addr)) {
                        if (pmd_set_huge(pmd, phys_addr + addr, prot))
                                continue;
                }
@@ -119,7 +119,7 @@ static inline int ioremap_pud_range(p4d_t *p4d, unsigned long addr,
                if (ioremap_pud_enabled() &&
                    ((next - addr) == PUD_SIZE) &&
                    IS_ALIGNED(phys_addr + addr, PUD_SIZE) &&
-                   pud_free_pmd_page(pud)) {
+                   pud_free_pmd_page(pud, addr)) {
                        if (pud_set_huge(pud, phys_addr + addr, prot))
                                continue;
                }