Skip to content

Commit 3a19109

Browse files
toshikaniKAGA-KOKO
authored andcommitted
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>
1 parent daf3e35 commit 3a19109

File tree

1 file changed

+14
-10
lines changed

1 file changed

+14
-10
lines changed

arch/x86/mm/pageattr.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ static int
468468
try_preserve_large_page(pte_t *kpte, unsigned long address,
469469
struct cpa_data *cpa)
470470
{
471-
unsigned long nextpage_addr, numpages, pmask, psize, addr, pfn;
471+
unsigned long nextpage_addr, numpages, pmask, psize, addr, pfn, old_pfn;
472472
pte_t new_pte, old_pte, *tmp;
473473
pgprot_t old_prot, new_prot, req_prot;
474474
int i, do_split = 1;
@@ -488,17 +488,21 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
488488

489489
switch (level) {
490490
case PG_LEVEL_2M:
491-
#ifdef CONFIG_X86_64
491+
old_prot = pmd_pgprot(*(pmd_t *)kpte);
492+
old_pfn = pmd_pfn(*(pmd_t *)kpte);
493+
break;
492494
case PG_LEVEL_1G:
493-
#endif
494-
psize = page_level_size(level);
495-
pmask = page_level_mask(level);
495+
old_prot = pud_pgprot(*(pud_t *)kpte);
496+
old_pfn = pud_pfn(*(pud_t *)kpte);
496497
break;
497498
default:
498499
do_split = -EINVAL;
499500
goto out_unlock;
500501
}
501502

503+
psize = page_level_size(level);
504+
pmask = page_level_mask(level);
505+
502506
/*
503507
* Calculate the number of pages, which fit into this large
504508
* page starting at address:
@@ -514,7 +518,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
514518
* up accordingly.
515519
*/
516520
old_pte = *kpte;
517-
old_prot = req_prot = pgprot_large_2_4k(pte_pgprot(old_pte));
521+
old_prot = req_prot = pgprot_large_2_4k(old_prot);
518522

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

542546
/*
543-
* old_pte points to the large page base address. So we need
547+
* old_pfn points to the large page base pfn. So we need
544548
* to add the offset of the virtual address:
545549
*/
546-
pfn = pte_pfn(old_pte) + ((address & (psize - 1)) >> PAGE_SHIFT);
550+
pfn = old_pfn + ((address & (psize - 1)) >> PAGE_SHIFT);
547551
cpa->pfn = pfn;
548552

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

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

0 commit comments

Comments
 (0)