diff options
Diffstat (limited to 'drivers/kvm/mmu.c')
-rw-r--r-- | drivers/kvm/mmu.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 069ce83f018e..d347e895736e 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c | |||
@@ -692,6 +692,15 @@ static void kvm_mmu_put_page(struct kvm_mmu_page *page, | |||
692 | mmu_page_remove_parent_pte(page, parent_pte); | 692 | mmu_page_remove_parent_pte(page, parent_pte); |
693 | } | 693 | } |
694 | 694 | ||
695 | static void kvm_mmu_reset_last_pte_updated(struct kvm *kvm) | ||
696 | { | ||
697 | int i; | ||
698 | |||
699 | for (i = 0; i < KVM_MAX_VCPUS; ++i) | ||
700 | if (kvm->vcpus[i]) | ||
701 | kvm->vcpus[i]->last_pte_updated = NULL; | ||
702 | } | ||
703 | |||
695 | static void kvm_mmu_zap_page(struct kvm *kvm, | 704 | static void kvm_mmu_zap_page(struct kvm *kvm, |
696 | struct kvm_mmu_page *page) | 705 | struct kvm_mmu_page *page) |
697 | { | 706 | { |
@@ -717,6 +726,7 @@ static void kvm_mmu_zap_page(struct kvm *kvm, | |||
717 | kvm_mmu_free_page(kvm, page); | 726 | kvm_mmu_free_page(kvm, page); |
718 | } else | 727 | } else |
719 | list_move(&page->link, &kvm->active_mmu_pages); | 728 | list_move(&page->link, &kvm->active_mmu_pages); |
729 | kvm_mmu_reset_last_pte_updated(kvm); | ||
720 | } | 730 | } |
721 | 731 | ||
722 | static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn) | 732 | static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn) |
@@ -1140,6 +1150,13 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, | |||
1140 | offset_in_pte); | 1150 | offset_in_pte); |
1141 | } | 1151 | } |
1142 | 1152 | ||
1153 | static bool last_updated_pte_accessed(struct kvm_vcpu *vcpu) | ||
1154 | { | ||
1155 | u64 *spte = vcpu->last_pte_updated; | ||
1156 | |||
1157 | return !!(spte && (*spte & PT_ACCESSED_MASK)); | ||
1158 | } | ||
1159 | |||
1143 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | 1160 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, |
1144 | const u8 *new, int bytes) | 1161 | const u8 *new, int bytes) |
1145 | { | 1162 | { |
@@ -1160,13 +1177,15 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1160 | 1177 | ||
1161 | pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); | 1178 | pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); |
1162 | kvm_mmu_audit(vcpu, "pre pte write"); | 1179 | kvm_mmu_audit(vcpu, "pre pte write"); |
1163 | if (gfn == vcpu->last_pt_write_gfn) { | 1180 | if (gfn == vcpu->last_pt_write_gfn |
1181 | && !last_updated_pte_accessed(vcpu)) { | ||
1164 | ++vcpu->last_pt_write_count; | 1182 | ++vcpu->last_pt_write_count; |
1165 | if (vcpu->last_pt_write_count >= 3) | 1183 | if (vcpu->last_pt_write_count >= 3) |
1166 | flooded = 1; | 1184 | flooded = 1; |
1167 | } else { | 1185 | } else { |
1168 | vcpu->last_pt_write_gfn = gfn; | 1186 | vcpu->last_pt_write_gfn = gfn; |
1169 | vcpu->last_pt_write_count = 1; | 1187 | vcpu->last_pt_write_count = 1; |
1188 | vcpu->last_pte_updated = NULL; | ||
1170 | } | 1189 | } |
1171 | index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; | 1190 | index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; |
1172 | bucket = &vcpu->kvm->mmu_page_hash[index]; | 1191 | bucket = &vcpu->kvm->mmu_page_hash[index]; |