diff options
-rw-r--r-- | arch/x86/kvm/mmu.c | 12 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 12 | ||||
-rw-r--r-- | include/asm-x86/kvm_host.h | 1 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 2 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 23 |
5 files changed, 48 insertions, 2 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index f7541fe22cd8..103d008dab8b 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -667,7 +667,8 @@ static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn) | |||
667 | index = kvm_page_table_hashfn(gfn); | 667 | index = kvm_page_table_hashfn(gfn); |
668 | bucket = &kvm->arch.mmu_page_hash[index]; | 668 | bucket = &kvm->arch.mmu_page_hash[index]; |
669 | hlist_for_each_entry(sp, node, bucket, hash_link) | 669 | hlist_for_each_entry(sp, node, bucket, hash_link) |
670 | if (sp->gfn == gfn && !sp->role.metaphysical) { | 670 | if (sp->gfn == gfn && !sp->role.metaphysical |
671 | && !sp->role.invalid) { | ||
671 | pgprintk("%s: found role %x\n", | 672 | pgprintk("%s: found role %x\n", |
672 | __FUNCTION__, sp->role.word); | 673 | __FUNCTION__, sp->role.word); |
673 | return sp; | 674 | return sp; |
@@ -792,8 +793,11 @@ static void kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp) | |||
792 | if (!sp->root_count) { | 793 | if (!sp->root_count) { |
793 | hlist_del(&sp->hash_link); | 794 | hlist_del(&sp->hash_link); |
794 | kvm_mmu_free_page(kvm, sp); | 795 | kvm_mmu_free_page(kvm, sp); |
795 | } else | 796 | } else { |
796 | list_move(&sp->link, &kvm->arch.active_mmu_pages); | 797 | list_move(&sp->link, &kvm->arch.active_mmu_pages); |
798 | sp->role.invalid = 1; | ||
799 | kvm_reload_remote_mmus(kvm); | ||
800 | } | ||
797 | kvm_mmu_reset_last_pte_updated(kvm); | 801 | kvm_mmu_reset_last_pte_updated(kvm); |
798 | } | 802 | } |
799 | 803 | ||
@@ -1073,6 +1077,8 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu) | |||
1073 | 1077 | ||
1074 | sp = page_header(root); | 1078 | sp = page_header(root); |
1075 | --sp->root_count; | 1079 | --sp->root_count; |
1080 | if (!sp->root_count && sp->role.invalid) | ||
1081 | kvm_mmu_zap_page(vcpu->kvm, sp); | ||
1076 | vcpu->arch.mmu.root_hpa = INVALID_PAGE; | 1082 | vcpu->arch.mmu.root_hpa = INVALID_PAGE; |
1077 | spin_unlock(&vcpu->kvm->mmu_lock); | 1083 | spin_unlock(&vcpu->kvm->mmu_lock); |
1078 | return; | 1084 | return; |
@@ -1085,6 +1091,8 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu) | |||
1085 | root &= PT64_BASE_ADDR_MASK; | 1091 | root &= PT64_BASE_ADDR_MASK; |
1086 | sp = page_header(root); | 1092 | sp = page_header(root); |
1087 | --sp->root_count; | 1093 | --sp->root_count; |
1094 | if (!sp->root_count && sp->role.invalid) | ||
1095 | kvm_mmu_zap_page(vcpu->kvm, sp); | ||
1088 | } | 1096 | } |
1089 | vcpu->arch.mmu.pae_root[i] = INVALID_PAGE; | 1097 | vcpu->arch.mmu.pae_root[i] = INVALID_PAGE; |
1090 | } | 1098 | } |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0dd038e7392b..e8e64927bddc 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -2658,6 +2658,10 @@ preempted: | |||
2658 | kvm_x86_ops->guest_debug_pre(vcpu); | 2658 | kvm_x86_ops->guest_debug_pre(vcpu); |
2659 | 2659 | ||
2660 | again: | 2660 | again: |
2661 | if (vcpu->requests) | ||
2662 | if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) | ||
2663 | kvm_mmu_unload(vcpu); | ||
2664 | |||
2661 | r = kvm_mmu_reload(vcpu); | 2665 | r = kvm_mmu_reload(vcpu); |
2662 | if (unlikely(r)) | 2666 | if (unlikely(r)) |
2663 | goto out; | 2667 | goto out; |
@@ -2689,6 +2693,14 @@ again: | |||
2689 | goto out; | 2693 | goto out; |
2690 | } | 2694 | } |
2691 | 2695 | ||
2696 | if (vcpu->requests) | ||
2697 | if (test_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) { | ||
2698 | local_irq_enable(); | ||
2699 | preempt_enable(); | ||
2700 | r = 1; | ||
2701 | goto out; | ||
2702 | } | ||
2703 | |||
2692 | if (signal_pending(current)) { | 2704 | if (signal_pending(current)) { |
2693 | local_irq_enable(); | 2705 | local_irq_enable(); |
2694 | preempt_enable(); | 2706 | preempt_enable(); |
diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h index 935ffa4db9f4..8c3f74b73524 100644 --- a/include/asm-x86/kvm_host.h +++ b/include/asm-x86/kvm_host.h | |||
@@ -141,6 +141,7 @@ union kvm_mmu_page_role { | |||
141 | unsigned pad_for_nice_hex_output:6; | 141 | unsigned pad_for_nice_hex_output:6; |
142 | unsigned metaphysical:1; | 142 | unsigned metaphysical:1; |
143 | unsigned access:3; | 143 | unsigned access:3; |
144 | unsigned invalid:1; | ||
144 | }; | 145 | }; |
145 | }; | 146 | }; |
146 | 147 | ||
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index eb88d32dd5c7..994278fb5883 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -37,6 +37,7 @@ | |||
37 | #define KVM_REQ_TLB_FLUSH 0 | 37 | #define KVM_REQ_TLB_FLUSH 0 |
38 | #define KVM_REQ_MIGRATE_TIMER 1 | 38 | #define KVM_REQ_MIGRATE_TIMER 1 |
39 | #define KVM_REQ_REPORT_TPR_ACCESS 2 | 39 | #define KVM_REQ_REPORT_TPR_ACCESS 2 |
40 | #define KVM_REQ_MMU_RELOAD 3 | ||
40 | 41 | ||
41 | struct kvm_vcpu; | 42 | struct kvm_vcpu; |
42 | extern struct kmem_cache *kvm_vcpu_cache; | 43 | extern struct kmem_cache *kvm_vcpu_cache; |
@@ -190,6 +191,7 @@ void kvm_resched(struct kvm_vcpu *vcpu); | |||
190 | void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); | 191 | void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); |
191 | void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); | 192 | void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); |
192 | void kvm_flush_remote_tlbs(struct kvm *kvm); | 193 | void kvm_flush_remote_tlbs(struct kvm *kvm); |
194 | void kvm_reload_remote_mmus(struct kvm *kvm); | ||
193 | 195 | ||
194 | long kvm_arch_dev_ioctl(struct file *filp, | 196 | long kvm_arch_dev_ioctl(struct file *filp, |
195 | unsigned int ioctl, unsigned long arg); | 197 | unsigned int ioctl, unsigned long arg); |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index cf6df5167af6..c41eb57ce29b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -119,6 +119,29 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) | |||
119 | smp_call_function_mask(cpus, ack_flush, NULL, 1); | 119 | smp_call_function_mask(cpus, ack_flush, NULL, 1); |
120 | } | 120 | } |
121 | 121 | ||
122 | void kvm_reload_remote_mmus(struct kvm *kvm) | ||
123 | { | ||
124 | int i, cpu; | ||
125 | cpumask_t cpus; | ||
126 | struct kvm_vcpu *vcpu; | ||
127 | |||
128 | cpus_clear(cpus); | ||
129 | for (i = 0; i < KVM_MAX_VCPUS; ++i) { | ||
130 | vcpu = kvm->vcpus[i]; | ||
131 | if (!vcpu) | ||
132 | continue; | ||
133 | if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) | ||
134 | continue; | ||
135 | cpu = vcpu->cpu; | ||
136 | if (cpu != -1 && cpu != raw_smp_processor_id()) | ||
137 | cpu_set(cpu, cpus); | ||
138 | } | ||
139 | if (cpus_empty(cpus)) | ||
140 | return; | ||
141 | smp_call_function_mask(cpus, ack_flush, NULL, 1); | ||
142 | } | ||
143 | |||
144 | |||
122 | int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) | 145 | int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) |
123 | { | 146 | { |
124 | struct page *page; | 147 | struct page *page; |