lkml.org 
[lkml]   [2015]   [Sep]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[tip:x86/mm] x86/mm: Fix try_preserve_large_page() to handle large PAT bit
    Commit-ID:  3a19109efbfa7d887996a74257556a46e00525c2
    Gitweb: http://git.kernel.org/tip/3a19109efbfa7d887996a74257556a46e00525c2
    Author: Toshi Kani <toshi.kani@hpe.com>
    AuthorDate: Thu, 17 Sep 2015 12:24:22 -0600
    Committer: Thomas Gleixner <tglx@linutronix.de>
    CommitDate: Tue, 22 Sep 2015 21:27:33 +0200

    x86/mm: Fix try_preserve_large_page() to handle large PAT bit

    try_preserve_large_page() is called from __change_page_attr() to
    change the mapping attribute of a given large page. This function
    uses pte_pfn() and pte_pgprot() for PUD/PMD, which do not handle
    the large PAT bit properly.

    Fix try_preserve_large_page() by using the corresponding pud/pmd
    prot/pfn interfaces.

    Also remove '#ifdef CONFIG_X86_64', which is not necessary.

    Signed-off-by: Toshi Kani <toshi.kani@hpe.com>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Cc: Juergen Gross <jgross@suse.com>
    Cc: H. Peter Anvin <hpa@zytor.com>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: Borislav Petkov <bp@alien8.de>
    Cc: Konrad Wilk <konrad.wilk@oracle.com>
    Cc: Robert Elliot <elliott@hpe.com>
    Cc: linux-mm@kvack.org
    Link: http://lkml.kernel.org/r/1442514264-12475-10-git-send-email-toshi.kani@hpe.com
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    ---
    arch/x86/mm/pageattr.c | 24 ++++++++++++++----------
    1 file changed, 14 insertions(+), 10 deletions(-)

    diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
    index 1441368..3f61271 100644
    --- a/arch/x86/mm/pageattr.c
    +++ b/arch/x86/mm/pageattr.c
    @@ -468,7 +468,7 @@ static int
    try_preserve_large_page(pte_t *kpte, unsigned long address,
    struct cpa_data *cpa)
    {
    - unsigned long nextpage_addr, numpages, pmask, psize, addr, pfn;
    + unsigned long nextpage_addr, numpages, pmask, psize, addr, pfn, old_pfn;
    pte_t new_pte, old_pte, *tmp;
    pgprot_t old_prot, new_prot, req_prot;
    int i, do_split = 1;
    @@ -488,17 +488,21 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,

    switch (level) {
    case PG_LEVEL_2M:
    -#ifdef CONFIG_X86_64
    + old_prot = pmd_pgprot(*(pmd_t *)kpte);
    + old_pfn = pmd_pfn(*(pmd_t *)kpte);
    + break;
    case PG_LEVEL_1G:
    -#endif
    - psize = page_level_size(level);
    - pmask = page_level_mask(level);
    + old_prot = pud_pgprot(*(pud_t *)kpte);
    + old_pfn = pud_pfn(*(pud_t *)kpte);
    break;
    default:
    do_split = -EINVAL;
    goto out_unlock;
    }

    + psize = page_level_size(level);
    + pmask = page_level_mask(level);
    +
    /*
    * Calculate the number of pages, which fit into this large
    * page starting at address:
    @@ -514,7 +518,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
    * up accordingly.
    */
    old_pte = *kpte;
    - old_prot = req_prot = pgprot_large_2_4k(pte_pgprot(old_pte));
    + old_prot = req_prot = pgprot_large_2_4k(old_prot);

    pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr);
    pgprot_val(req_prot) |= pgprot_val(cpa->mask_set);
    @@ -540,10 +544,10 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
    req_prot = canon_pgprot(req_prot);

    /*
    - * old_pte points to the large page base address. So we need
    + * old_pfn points to the large page base pfn. So we need
    * to add the offset of the virtual address:
    */
    - pfn = pte_pfn(old_pte) + ((address & (psize - 1)) >> PAGE_SHIFT);
    + pfn = old_pfn + ((address & (psize - 1)) >> PAGE_SHIFT);
    cpa->pfn = pfn;

    new_prot = static_protections(req_prot, address, pfn);
    @@ -554,7 +558,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
    * the pages in the range we try to preserve:
    */
    addr = address & pmask;
    - pfn = pte_pfn(old_pte);
    + pfn = old_pfn;
    for (i = 0; i < (psize >> PAGE_SHIFT); i++, addr += PAGE_SIZE, pfn++) {
    pgprot_t chk_prot = static_protections(req_prot, addr, pfn);

    @@ -584,7 +588,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
    * The address is aligned and the number of pages
    * covers the full page.
    */
    - new_pte = pfn_pte(pte_pfn(old_pte), new_prot);
    + new_pte = pfn_pte(old_pfn, new_prot);
    __set_pmd_pte(kpte, address, new_pte);
    cpa->flags |= CPA_FLUSHTLB;
    do_split = 0;

    \
     
     \ /
      Last update: 2015-09-22 22:01    [W:4.120 / U:0.000 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site