x86: don't apply __supported_pte_mask to non-present ptes
authorJeremy Fitzhardinge <jeremy@goop.org>
Thu, 5 Feb 2009 02:33:38 +0000 (18:33 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 5 Feb 2009 05:33:09 +0000 (21:33 -0800)
commitb534816b552d35bbd3c60702139ed5c7da2f55c2
tree1e48095368b05b498264105757e6d79e78dace62
parent4560839939f4b4a96e21e80584f87308ac93c1da
x86: don't apply __supported_pte_mask to non-present ptes

On an x86 system which doesn't support global mappings,
__supported_pte_mask has _PAGE_GLOBAL clear, to make sure it never
appears in the PTE.  pfn_pte() and so on will enforce it with:

static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
{
return __pte((((phys_addr_t)page_nr << PAGE_SHIFT) |
      pgprot_val(pgprot)) & __supported_pte_mask);
}

However, we overload _PAGE_GLOBAL with _PAGE_PROTNONE on non-present
ptes to distinguish them from swap entries.  However, applying
__supported_pte_mask indiscriminately will clear the bit and corrupt the
pte.

I guess the best fix is to only apply __supported_pte_mask to present
ptes.  This seems like the right solution to me, as it means we can
completely ignore the issue of overlaps between the present pte bits and
the non-present pte-as-swap entry use of the bits.

__supported_pte_mask contains the set of flags we support on the
current hardware.  We also use bits in the pte for things like
logically present ptes with no permissions, and swap entries for
swapped out pages.  We should only apply __supported_pte_mask to
present ptes, because otherwise we may destroy other information being
stored in the ptes.

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/xen/page.h