aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorNadav Amit <namit@cs.technion.ac.il>2014-04-17 20:35:08 -0400
committerMarcelo Tosatti <mtosatti@redhat.com>2014-04-23 16:46:52 -0400
commit671bd9934a861288a248b051751061b11654aef9 (patch)
treea245e44f34cb15e7fc5ec237c73133f5a56f0e35 /arch/x86/kvm
parente0ba1a6ffcfe8dc95586943bbe56badb1459bf25 (diff)
KVM: x86: Fix wrong/stuck PMU when guest does not use PMI
If a guest enables a performance counter but does not enable PMI, the hypervisor currently does not reprogram the performance counter once it overflows. As a result the host performance counter is kept with the original sampling period which was configured according to the value of the guest's counter when the counter was enabled. Such behaviour can cause very bad consequences. The most distrubing one can cause the guest not to make any progress at all, and keep exiting due to host PMI before any guest instructions is exeucted. This situation occurs when the performance counter holds a very high value when the guest enables the performance counter. As a result the host's sampling period is configured to be very short. The host then never reconfigures the sampling period and get stuck at entry->PMI->exit loop. We encountered such a scenario in our experiments. The solution is to reprogram the counter even if the guest does not use PMI. Signed-off-by: Nadav Amit <namit@cs.technion.ac.il> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/pmu.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 5c4f63151b4d..cbecaa90399c 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -108,7 +108,10 @@ static void kvm_perf_overflow(struct perf_event *perf_event,
108{ 108{
109 struct kvm_pmc *pmc = perf_event->overflow_handler_context; 109 struct kvm_pmc *pmc = perf_event->overflow_handler_context;
110 struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu; 110 struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
111 __set_bit(pmc->idx, (unsigned long *)&pmu->global_status); 111 if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) {
112 __set_bit(pmc->idx, (unsigned long *)&pmu->global_status);
113 kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
114 }
112} 115}
113 116
114static void kvm_perf_overflow_intr(struct perf_event *perf_event, 117static void kvm_perf_overflow_intr(struct perf_event *perf_event,
@@ -117,7 +120,7 @@ static void kvm_perf_overflow_intr(struct perf_event *perf_event,
117 struct kvm_pmc *pmc = perf_event->overflow_handler_context; 120 struct kvm_pmc *pmc = perf_event->overflow_handler_context;
118 struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu; 121 struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
119 if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) { 122 if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) {
120 kvm_perf_overflow(perf_event, data, regs); 123 __set_bit(pmc->idx, (unsigned long *)&pmu->global_status);
121 kvm_make_request(KVM_REQ_PMU, pmc->vcpu); 124 kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
122 /* 125 /*
123 * Inject PMI. If vcpu was in a guest mode during NMI PMI 126 * Inject PMI. If vcpu was in a guest mode during NMI PMI