提交 671bd993 编写于 作者: N Nadav Amit 提交者: Marcelo Tosatti

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: NNadav Amit <namit@cs.technion.ac.il>
Signed-off-by: NMarcelo Tosatti <mtosatti@redhat.com>
上级 e0ba1a6f
...@@ -108,7 +108,10 @@ static void kvm_perf_overflow(struct perf_event *perf_event, ...@@ -108,7 +108,10 @@ static void kvm_perf_overflow(struct perf_event *perf_event,
{ {
struct kvm_pmc *pmc = perf_event->overflow_handler_context; struct kvm_pmc *pmc = perf_event->overflow_handler_context;
struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu; struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
__set_bit(pmc->idx, (unsigned long *)&pmu->global_status); if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) {
__set_bit(pmc->idx, (unsigned long *)&pmu->global_status);
kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
}
} }
static void kvm_perf_overflow_intr(struct perf_event *perf_event, static 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,7 +120,7 @@ static void kvm_perf_overflow_intr(struct perf_event *perf_event,
struct kvm_pmc *pmc = perf_event->overflow_handler_context; struct kvm_pmc *pmc = perf_event->overflow_handler_context;
struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu; struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) { if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) {
kvm_perf_overflow(perf_event, data, regs); __set_bit(pmc->idx, (unsigned long *)&pmu->global_status);
kvm_make_request(KVM_REQ_PMU, pmc->vcpu); kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
/* /*
* Inject PMI. If vcpu was in a guest mode during NMI PMI * Inject PMI. If vcpu was in a guest mode during NMI PMI
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册