KVM: x86/pmu: Reset the PMU, i.e. stop counters, before refreshing
authorSean Christopherson <seanjc@google.com>
Fri, 3 Nov 2023 23:05:37 +0000 (16:05 -0700)
committerSean Christopherson <seanjc@google.com>
Thu, 30 Nov 2023 20:52:54 +0000 (12:52 -0800)
Stop all counters and release all perf events before refreshing the vPMU,
i.e. before reconfiguring the vPMU to respond to changes in the vCPU
model.

Clear need_cleanup in kvm_pmu_reset() as well so that KVM doesn't
prematurely stop counters, e.g. if KVM enters the guest and enables
counters before the vCPU is scheduled out.

Cc: stable@vger.kernel.org
Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Link: https://lore.kernel.org/r/20231103230541.352265-3-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/pmu.c

index 027e9c3c2b93e1fce76c69cee2f2cc7494fa018a..dc8e8e907cfbfbc0013fde4f3ad67842c74cc5b5 100644 (file)
@@ -657,25 +657,14 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        return 0;
 }
 
-/* refresh PMU settings. This function generally is called when underlying
- * settings are changed (such as changes of PMU CPUID by guest VMs), which
- * should rarely happen.
- */
-void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
-{
-       if (KVM_BUG_ON(kvm_vcpu_has_run(vcpu), vcpu->kvm))
-               return;
-
-       bitmap_zero(vcpu_to_pmu(vcpu)->all_valid_pmc_idx, X86_PMC_IDX_MAX);
-       static_call(kvm_x86_pmu_refresh)(vcpu);
-}
-
 void kvm_pmu_reset(struct kvm_vcpu *vcpu)
 {
        struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
        struct kvm_pmc *pmc;
        int i;
 
+       pmu->need_cleanup = false;
+
        bitmap_zero(pmu->reprogram_pmi, X86_PMC_IDX_MAX);
 
        for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) {
@@ -695,6 +684,26 @@ void kvm_pmu_reset(struct kvm_vcpu *vcpu)
        static_call_cond(kvm_x86_pmu_reset)(vcpu);
 }
 
+
+/*
+ * Refresh the PMU configuration for the vCPU, e.g. if userspace changes CPUID
+ * and/or PERF_CAPABILITIES.
+ */
+void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
+{
+       if (KVM_BUG_ON(kvm_vcpu_has_run(vcpu), vcpu->kvm))
+               return;
+
+       /*
+        * Stop/release all existing counters/events before realizing the new
+        * vPMU model.
+        */
+       kvm_pmu_reset(vcpu);
+
+       bitmap_zero(vcpu_to_pmu(vcpu)->all_valid_pmc_idx, X86_PMC_IDX_MAX);
+       static_call(kvm_x86_pmu_refresh)(vcpu);
+}
+
 void kvm_pmu_init(struct kvm_vcpu *vcpu)
 {
        struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);