lkml.org 
[lkml]   [2018]   [Aug]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.18 22/22] x86/mm: Add TLB purge to free pmd/pte page interfaces
    Date
    4.18-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Toshi Kani <toshi.kani@hpe.com>

    commit 5e0fb5df2ee871b841f96f9cb6a7f2784e96aa4e upstream.

    ioremap() calls pud_free_pmd_page() / pmd_free_pte_page() when it creates
    a pud / pmd map. The following preconditions are met at their entry.
    - All pte entries for a target pud/pmd address range have been cleared.
    - System-wide TLB purges have been peformed for a target pud/pmd address
    range.

    The preconditions assure that there is no stale TLB entry for the range.
    Speculation may not cache TLB entries since it requires all levels of page
    entries, including ptes, to have P & A-bits set for an associated address.
    However, speculation may cache pud/pmd entries (paging-structure caches)
    when they have P-bit set.

    Add a system-wide TLB purge (INVLPG) to a single page after clearing
    pud/pmd entry's P-bit.

    SDM 4.10.4.1, Operation that Invalidate TLBs and Paging-Structure Caches,
    states that:
    INVLPG invalidates all paging-structure caches associated with the
    current PCID regardless of the liner addresses to which they correspond.

    Fixes: 28ee90fe6048 ("x86/mm: implement free pmd/pte page interfaces")
    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: cpandya@codeaurora.org
    Cc: linux-mm@kvack.org
    Cc: linux-arm-kernel@lists.infradead.org
    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-4-toshi.kani@hpe.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/x86/mm/pgtable.c | 38 +++++++++++++++++++++++++++++++-------
    1 file changed, 31 insertions(+), 7 deletions(-)

    --- a/arch/x86/mm/pgtable.c
    +++ b/arch/x86/mm/pgtable.c
    @@ -725,24 +725,44 @@ int pmd_clear_huge(pmd_t *pmd)
    * @pud: Pointer to a PUD.
    * @addr: Virtual address associated with pud.
    *
    - * Context: The pud range has been unmaped and TLB purged.
    + * Context: The pud range has been unmapped and TLB purged.
    * Return: 1 if clearing the entry succeeded. 0 otherwise.
    + *
    + * NOTE: Callers must allow a single page allocation.
    */
    int pud_free_pmd_page(pud_t *pud, unsigned long addr)
    {
    - pmd_t *pmd;
    + pmd_t *pmd, *pmd_sv;
    + pte_t *pte;
    int i;

    if (pud_none(*pud))
    return 1;

    pmd = (pmd_t *)pud_page_vaddr(*pud);
    -
    - for (i = 0; i < PTRS_PER_PMD; i++)
    - if (!pmd_free_pte_page(&pmd[i], addr + (i * PMD_SIZE)))
    - return 0;
    + pmd_sv = (pmd_t *)__get_free_page(GFP_KERNEL);
    + if (!pmd_sv)
    + return 0;
    +
    + for (i = 0; i < PTRS_PER_PMD; i++) {
    + pmd_sv[i] = pmd[i];
    + if (!pmd_none(pmd[i]))
    + pmd_clear(&pmd[i]);
    + }

    pud_clear(pud);
    +
    + /* INVLPG to clear all paging-structure caches */
    + flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1);
    +
    + for (i = 0; i < PTRS_PER_PMD; i++) {
    + if (!pmd_none(pmd_sv[i])) {
    + pte = (pte_t *)pmd_page_vaddr(pmd_sv[i]);
    + free_page((unsigned long)pte);
    + }
    + }
    +
    + free_page((unsigned long)pmd_sv);
    free_page((unsigned long)pmd);

    return 1;
    @@ -753,7 +773,7 @@ int pud_free_pmd_page(pud_t *pud, unsign
    * @pmd: Pointer to a PMD.
    * @addr: Virtual address associated with pmd.
    *
    - * Context: The pmd range has been unmaped and TLB purged.
    + * Context: The pmd range has been unmapped and TLB purged.
    * Return: 1 if clearing the entry succeeded. 0 otherwise.
    */
    int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
    @@ -765,6 +785,10 @@ int pmd_free_pte_page(pmd_t *pmd, unsign

    pte = (pte_t *)pmd_page_vaddr(*pmd);
    pmd_clear(pmd);
    +
    + /* INVLPG to clear all paging-structure caches */
    + flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1);
    +
    free_page((unsigned long)pte);

    return 1;

    \
     
     \ /
      Last update: 2018-08-16 20:50    [W:4.681 / U:0.644 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site