diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2009-03-23 17:51:33 -0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-05-02 10:57:10 -0700 |
commit | 2ef5df79ae93e27162a3ff9f9326cc53ef42a970 (patch) | |
tree | 0ec1668c9b452b722da0f4ff417a434340e8c204 /arch | |
parent | 3899af53551a9d5f0b316b9b5d1afba2ac47d0a9 (diff) |
KVM: MMU: handle large host sptes on invlpg/resync
(cherry picked from 87917239204d67a316cb89751750f86c9ed3640b)
The invlpg and sync walkers lack knowledge of large host sptes,
descending to non-existant pagetable level.
Stop at directory level in such case.
Fixes SMP Windows XP with hugepages.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/mmu.c | 2 | ||||
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 8 |
2 files changed, 7 insertions, 3 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 0d2918632b8..c3c0191b37f 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -981,7 +981,7 @@ static int mmu_unsync_walk(struct kvm_mmu_page *sp, for_each_unsync_children(sp->unsync_child_bitmap, i) { u64 ent = sp->spt[i]; - if (is_shadow_present_pte(ent)) { + if (is_shadow_present_pte(ent) && !is_large_pte(ent)) { struct kvm_mmu_page *child; child = page_header(ent & PT64_BASE_ADDR_MASK); diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 84eee43bbe7..9b5355ef980 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -467,9 +467,13 @@ static int FNAME(shadow_invlpg_entry)(struct kvm_shadow_walk *_sw, u64 *sptep, int level) { - if (level == PT_PAGE_TABLE_LEVEL) { - if (is_shadow_present_pte(*sptep)) + if (level == PT_PAGE_TABLE_LEVEL || + ((level == PT_DIRECTORY_LEVEL) && is_large_pte(*sptep))) { + if (is_shadow_present_pte(*sptep)) { rmap_remove(vcpu->kvm, sptep); + if (is_large_pte(*sptep)) + --vcpu->kvm->stat.lpages; + } set_shadow_pte(sptep, shadow_trap_nonpresent_pte); return 1; } |