aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiao Guangrong <xiaoguangrong@cn.fujitsu.com>2011-01-12 02:40:31 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2011-03-17 12:08:26 -0400
commit6b7e2d0991489559a1df4500d77f7b76c4607ed0 (patch)
treeb82e941c3ca4d519c71577ad21807af4d02b0679
parentd48ead8b0b48862a87138d04efb7580a1a25beb5 (diff)
KVM: Add "exiting guest mode" state
Currently we keep track of only two states: guest mode and host mode. This patch adds an "exiting guest mode" state that tells us that an IPI will happen soon, so unless we need to wait for the IPI, we can avoid it completely. Also 1: No need atomically to read/write ->mode in vcpu's thread 2: reorganize struct kvm_vcpu to make ->mode and ->requests in the same cache line explicitly Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-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))