diff options
author | Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> | 2010-07-15 23:25:17 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-08-01 23:40:58 -0400 |
commit | 9ed5520dd3c9cb79c25f95fce9c57b87637d0fb7 (patch) | |
tree | 32a983f23b3aa4dba5dea64a57f1b96126afe92a /arch/x86/kvm/mmu.c | |
parent | daa3db693ce925a14b7e17ab6f306dc0e6a5342c (diff) |
KVM: MMU: fix page dirty tracking lost while sync page
In sync-page path, if spte.writable is changed, it will lose page dirty
tracking, for example:
assume spte.writable = 0 in a unsync-page, when it's synced, it map spte
to writable(that is spte.writable = 1), later guest write spte.gfn, it means
spte.gfn is dirty, then guest changed this mapping to read-only, after it's
synced, spte.writable = 0
So, when host release the spte, it detect spte.writable = 0 and not mark page
dirty
Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/mmu.c')
-rw-r--r-- | arch/x86/kvm/mmu.c | 10 |
1 files changed, 3 insertions, 7 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 9b3b916ebeae..a04756a26fe2 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -1985,6 +1985,8 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1985 | mark_page_dirty(vcpu->kvm, gfn); | 1985 | mark_page_dirty(vcpu->kvm, gfn); |
1986 | 1986 | ||
1987 | set_pte: | 1987 | set_pte: |
1988 | if (is_writable_pte(*sptep) && !is_writable_pte(spte)) | ||
1989 | kvm_set_pfn_dirty(pfn); | ||
1988 | update_spte(sptep, spte); | 1990 | update_spte(sptep, spte); |
1989 | done: | 1991 | done: |
1990 | return ret; | 1992 | return ret; |
@@ -1998,7 +2000,6 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1998 | bool reset_host_protection) | 2000 | bool reset_host_protection) |
1999 | { | 2001 | { |
2000 | int was_rmapped = 0; | 2002 | int was_rmapped = 0; |
2001 | int was_writable = is_writable_pte(*sptep); | ||
2002 | int rmap_count; | 2003 | int rmap_count; |
2003 | 2004 | ||
2004 | pgprintk("%s: spte %llx access %x write_fault %d" | 2005 | pgprintk("%s: spte %llx access %x write_fault %d" |
@@ -2048,15 +2049,10 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
2048 | page_header_update_slot(vcpu->kvm, sptep, gfn); | 2049 | page_header_update_slot(vcpu->kvm, sptep, gfn); |
2049 | if (!was_rmapped) { | 2050 | if (!was_rmapped) { |
2050 | rmap_count = rmap_add(vcpu, sptep, gfn); | 2051 | rmap_count = rmap_add(vcpu, sptep, gfn); |
2051 | kvm_release_pfn_clean(pfn); | ||
2052 | if (rmap_count > RMAP_RECYCLE_THRESHOLD) | 2052 | if (rmap_count > RMAP_RECYCLE_THRESHOLD) |
2053 | rmap_recycle(vcpu, sptep, gfn); | 2053 | rmap_recycle(vcpu, sptep, gfn); |
2054 | } else { | ||
2055 | if (was_writable) | ||
2056 | kvm_release_pfn_dirty(pfn); | ||
2057 | else | ||
2058 | kvm_release_pfn_clean(pfn); | ||
2059 | } | 2054 | } |
2055 | kvm_release_pfn_clean(pfn); | ||
2060 | if (speculative) { | 2056 | if (speculative) { |
2061 | vcpu->arch.last_pte_updated = sptep; | 2057 | vcpu->arch.last_pte_updated = sptep; |
2062 | vcpu->arch.last_pte_gfn = gfn; | 2058 | vcpu->arch.last_pte_gfn = gfn; |