Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 359113
b: refs/heads/master
c: a8aed3e
h: refs/heads/master
i:
  359111: f1d237c
v: v3
  • Loading branch information
Andrea Arcangeli authored and Ingo Molnar committed Feb 24, 2013
1 parent 80197d0 commit 7f7fbdd
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 954f857187033ee3d3704a8206715cf354c38898
refs/heads/master: a8aed3e0752b4beb2e37cbed6df69faae88268da
50 changes: 47 additions & 3 deletions trunk/arch/x86/mm/pageattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,19 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr);
pgprot_val(req_prot) |= pgprot_val(cpa->mask_set);

/*
* Set the PSE and GLOBAL flags only if the PRESENT flag is
* set otherwise pmd_present/pmd_huge will return true even on
* a non present pmd. The canon_pgprot will clear _PAGE_GLOBAL
* for the ancient hardware that doesn't support it.
*/
if (pgprot_val(new_prot) & _PAGE_PRESENT)
pgprot_val(new_prot) |= _PAGE_PSE | _PAGE_GLOBAL;
else
pgprot_val(new_prot) &= ~(_PAGE_PSE | _PAGE_GLOBAL);

new_prot = canon_pgprot(new_prot);

/*
* old_pte points to the large page base address. So we need
* to add the offset of the virtual address:
Expand Down Expand Up @@ -489,7 +502,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), canon_pgprot(new_prot));
new_pte = pfn_pte(pte_pfn(old_pte), new_prot);
__set_pmd_pte(kpte, address, new_pte);
cpa->flags |= CPA_FLUSHTLB;
do_split = 0;
Expand Down Expand Up @@ -540,16 +553,35 @@ static int split_large_page(pte_t *kpte, unsigned long address)
#ifdef CONFIG_X86_64
if (level == PG_LEVEL_1G) {
pfninc = PMD_PAGE_SIZE >> PAGE_SHIFT;
pgprot_val(ref_prot) |= _PAGE_PSE;
/*
* Set the PSE flags only if the PRESENT flag is set
* otherwise pmd_present/pmd_huge will return true
* even on a non present pmd.
*/
if (pgprot_val(ref_prot) & _PAGE_PRESENT)
pgprot_val(ref_prot) |= _PAGE_PSE;
else
pgprot_val(ref_prot) &= ~_PAGE_PSE;
}
#endif

/*
* Set the GLOBAL flags only if the PRESENT flag is set
* otherwise pmd/pte_present will return true even on a non
* present pmd/pte. The canon_pgprot will clear _PAGE_GLOBAL
* for the ancient hardware that doesn't support it.
*/
if (pgprot_val(ref_prot) & _PAGE_PRESENT)
pgprot_val(ref_prot) |= _PAGE_GLOBAL;
else
pgprot_val(ref_prot) &= ~_PAGE_GLOBAL;

/*
* Get the target pfn from the original entry:
*/
pfn = pte_pfn(*kpte);
for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
set_pte(&pbase[i], pfn_pte(pfn, ref_prot));
set_pte(&pbase[i], pfn_pte(pfn, canon_pgprot(ref_prot)));

if (address >= (unsigned long)__va(0) &&
address < (unsigned long)__va(max_low_pfn_mapped << PAGE_SHIFT))
Expand Down Expand Up @@ -659,6 +691,18 @@ static int __change_page_attr(struct cpa_data *cpa, int primary)

new_prot = static_protections(new_prot, address, pfn);

/*
* Set the GLOBAL flags only if the PRESENT flag is
* set otherwise pte_present will return true even on
* a non present pte. The canon_pgprot will clear
* _PAGE_GLOBAL for the ancient hardware that doesn't
* support it.
*/
if (pgprot_val(new_prot) & _PAGE_PRESENT)
pgprot_val(new_prot) |= _PAGE_GLOBAL;
else
pgprot_val(new_prot) &= ~_PAGE_GLOBAL;

/*
* We need to keep the pfn from the existing PTE,
* after all we're only going to change it's attributes
Expand Down

0 comments on commit 7f7fbdd

Please sign in to comment.