aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/ia64/kvm/kvm-ia64.c2
-rw-r--r--arch/x86/kvm/x86.c16
-rw-r--r--include/linux/kvm_host.h22
-rw-r--r--virt/kvm/kvm_main.c7
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,
98int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu); 98int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu);
99#endif 99#endif
100 100
101enum {
102 OUTSIDE_GUEST_MODE,
103 IN_GUEST_MODE,
104 EXITING_GUEST_MODE
105};
106
101struct kvm_vcpu { 107struct 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
150static 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))