diff options
-rw-r--r-- | arch/ia64/kvm/kvm-ia64.c | 2 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 16 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 22 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 7 |
4 files changed, 35 insertions, 12 deletions
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index 70d224d4264c..8213efe1998c 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c | |||
@@ -662,6 +662,7 @@ again: | |||
662 | goto vcpu_run_fail; | 662 | goto vcpu_run_fail; |
663 | 663 | ||
664 | srcu_read_unlock(&vcpu->kvm->srcu, idx); | 664 | srcu_read_unlock(&vcpu->kvm->srcu, idx); |
665 | vcpu->mode = IN_GUEST_MODE; | ||
665 | kvm_guest_enter(); | 666 | kvm_guest_enter(); |
666 | 667 | ||
667 | /* | 668 | /* |
@@ -683,6 +684,7 @@ again: | |||
683 | */ | 684 | */ |
684 | barrier(); | 685 | barrier(); |
685 | kvm_guest_exit(); | 686 | kvm_guest_exit(); |
687 | vcpu->mode = OUTSIDE_GUEST_MODE; | ||
686 | preempt_enable(); | 688 | preempt_enable(); |
687 | 689 | ||
688 | idx = srcu_read_lock(&vcpu->kvm->srcu); | 690 | idx = srcu_read_lock(&vcpu->kvm->srcu); |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5eccdba08bd0..a7f65aa6eef6 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -5210,14 +5210,18 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) | |||
5210 | kvm_load_guest_fpu(vcpu); | 5210 | kvm_load_guest_fpu(vcpu); |
5211 | kvm_load_guest_xcr0(vcpu); | 5211 | kvm_load_guest_xcr0(vcpu); |
5212 | 5212 | ||
5213 | atomic_set(&vcpu->guest_mode, 1); | 5213 | vcpu->mode = IN_GUEST_MODE; |
5214 | smp_wmb(); | 5214 | |
5215 | /* We should set ->mode before check ->requests, | ||
5216 | * see the comment in make_all_cpus_request. | ||
5217 | */ | ||
5218 | smp_mb(); | ||
5215 | 5219 | ||
5216 | local_irq_disable(); | 5220 | local_irq_disable(); |
5217 | 5221 | ||
5218 | if (!atomic_read(&vcpu->guest_mode) || vcpu->requests | 5222 | if (vcpu->mode == EXITING_GUEST_MODE || vcpu->requests |
5219 | || need_resched() || signal_pending(current)) { | 5223 | || need_resched() || signal_pending(current)) { |
5220 | atomic_set(&vcpu->guest_mode, 0); | 5224 | vcpu->mode = OUTSIDE_GUEST_MODE; |
5221 | smp_wmb(); | 5225 | smp_wmb(); |
5222 | local_irq_enable(); | 5226 | local_irq_enable(); |
5223 | preempt_enable(); | 5227 | preempt_enable(); |
@@ -5253,7 +5257,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) | |||
5253 | 5257 | ||
5254 | kvm_get_msr(vcpu, MSR_IA32_TSC, &vcpu->arch.last_guest_tsc); | 5258 | kvm_get_msr(vcpu, MSR_IA32_TSC, &vcpu->arch.last_guest_tsc); |
5255 | 5259 | ||
5256 | atomic_set(&vcpu->guest_mode, 0); | 5260 | vcpu->mode = OUTSIDE_GUEST_MODE; |
5257 | smp_wmb(); | 5261 | smp_wmb(); |
5258 | local_irq_enable(); | 5262 | local_irq_enable(); |
5259 | 5263 | ||
@@ -6157,7 +6161,7 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu) | |||
6157 | 6161 | ||
6158 | me = get_cpu(); | 6162 | me = get_cpu(); |
6159 | if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) | 6163 | if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) |
6160 | if (atomic_xchg(&vcpu->guest_mode, 0)) | 6164 | if (kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE) |
6161 | smp_send_reschedule(cpu); | 6165 | smp_send_reschedule(cpu); |
6162 | put_cpu(); | 6166 | put_cpu(); |
6163 | } | 6167 | } |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index b5021db21858..b99eacd988ab 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -98,19 +98,26 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn, | |||
98 | int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu); | 98 | int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu); |
99 | #endif | 99 | #endif |
100 | 100 | ||
101 | enum { | ||
102 | OUTSIDE_GUEST_MODE, | ||
103 | IN_GUEST_MODE, | ||
104 | EXITING_GUEST_MODE | ||
105 | }; | ||
106 | |||
101 | struct kvm_vcpu { | 107 | struct kvm_vcpu { |
102 | struct kvm *kvm; | 108 | struct kvm *kvm; |
103 | #ifdef CONFIG_PREEMPT_NOTIFIERS | 109 | #ifdef CONFIG_PREEMPT_NOTIFIERS |
104 | struct preempt_notifier preempt_notifier; | 110 | struct preempt_notifier preempt_notifier; |
105 | #endif | 111 | #endif |
112 | int cpu; | ||
106 | int vcpu_id; | 113 | int vcpu_id; |
107 | struct mutex mutex; | 114 | int srcu_idx; |
108 | int cpu; | 115 | int mode; |
109 | atomic_t guest_mode; | ||
110 | struct kvm_run *run; | ||
111 | unsigned long requests; | 116 | unsigned long requests; |
112 | unsigned long guest_debug; | 117 | unsigned long guest_debug; |
113 | int srcu_idx; | 118 | |
119 | struct mutex mutex; | ||
120 | struct kvm_run *run; | ||
114 | 121 | ||
115 | int fpu_active; | 122 | int fpu_active; |
116 | int guest_fpu_loaded, guest_xcr0_loaded; | 123 | int guest_fpu_loaded, guest_xcr0_loaded; |
@@ -140,6 +147,11 @@ struct kvm_vcpu { | |||
140 | struct kvm_vcpu_arch arch; | 147 | struct kvm_vcpu_arch arch; |
141 | }; | 148 | }; |
142 | 149 | ||
150 | static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu) | ||
151 | { | ||
152 | return cmpxchg(&vcpu->mode, IN_GUEST_MODE, EXITING_GUEST_MODE); | ||
153 | } | ||
154 | |||
143 | /* | 155 | /* |
144 | * Some of the bitops functions do not support too long bitmaps. | 156 | * Some of the bitops functions do not support too long bitmaps. |
145 | * This number must be determined not to exceed such limits. | 157 | * This number must be determined not to exceed such limits. |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index fd67bcde9980..19209f849cf7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -171,7 +171,12 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req) | |||
171 | if (kvm_make_check_request(req, vcpu)) | 171 | if (kvm_make_check_request(req, vcpu)) |
172 | continue; | 172 | continue; |
173 | cpu = vcpu->cpu; | 173 | cpu = vcpu->cpu; |
174 | if (cpus != NULL && cpu != -1 && cpu != me) | 174 | |
175 | /* Set ->requests bit before we read ->mode */ | ||
176 | smp_mb(); | ||
177 | |||
178 | if (cpus != NULL && cpu != -1 && cpu != me && | ||
179 | kvm_vcpu_exiting_guest_mode(vcpu) != OUTSIDE_GUEST_MODE) | ||
175 | cpumask_set_cpu(cpu, cpus); | 180 | cpumask_set_cpu(cpu, cpus); |
176 | } | 181 | } |
177 | if (unlikely(cpus == NULL)) | 182 | if (unlikely(cpus == NULL)) |