[PATCH 06/23] perf/x86: Restrict !exclude_guest events to host-owned counters

Zide Chen <[email protected]>
Newsgroups org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Kan Liang <[email protected]>

When PMU partitioning is enabled and a guest is running,
!exclude_guest events must be scheduled only on host-owned counters.

After guest exit, PMU partition constraints are no longer applied and
host events may use the full counter set.

Signed-off-by: Kan Liang <[email protected]>
Co-developed-by: Zide Chen <[email protected]>
Signed-off-by: Zide Chen <[email protected]>
---
 arch/x86/events/intel/core.c | 45 +++++++++++++++++++++++++++++++++---
 1 file changed, 42 insertions(+), 3 deletions(-)

diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 894f98eb871a..7951accfcf2c 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2814,6 +2814,13 @@ static void __intel_pmu_enable_all(int added, bool pmi)
 
 	if (!x86_pmu_partition_loaded(cpuc))
 	       intel_ctrl &= ~cpuc->intel_ctrl_guest_mask;
+	else if (pmi)
+		/*
+		 * Guest-owned bits are excluded here, not because of clobbering
+		 * global ctrl guest bits in non-root mode, but because guest
+		 * counter MSRs have not yet been saved by KVM in NMI context.
+		 */
+		intel_ctrl &= ~x86_pmu_current_partition_mask();
 
 	wrmsrq(MSR_CORE_PERF_GLOBAL_CTRL, intel_ctrl);
 
@@ -4448,6 +4455,31 @@ dyn_constraint(struct cpu_hw_events *cpuc, struct event_constraint *c, int idx)
 	return c;
 }
 
+/*
+ * Mask out guest-owned counters from a constraint when PMU partition has been
+ * entered, so !exclude_guest host events are not scheduled onto them while
+ * the CPU is in non-root mode.
+ */
+static struct event_constraint *
+part_constraint(struct cpu_hw_events *cpuc, int idx,
+		struct perf_event *event, struct event_constraint *c)
+{
+	/*
+	 * Skip &emptyconstraint: dyn_constraint() would clone it, breaking
+	 * the "c == &emptyconstraint" pointer checks callers rely on.
+	 */
+	if (!c->weight || c == &emptyconstraint)
+		return c;
+
+	if (x86_pmu_partition_loaded(cpuc)) {
+		c = dyn_constraint(cpuc, c, idx);
+		c->idxmsk64 &= ~x86_pmu_current_partition_mask();
+		c->weight = hweight64(c->idxmsk64);
+	}
+
+	return c;
+}
+
 static struct event_constraint *
 intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
 			   int idx, struct event_constraint *c)
@@ -4569,8 +4601,14 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
 		c2 = c1;
 	}
 
-	if (cpuc->excl_cntrs)
+	/*
+	 * No platform supports both PMU_FL_EXCL_CNTRS and PerfMon masking
+	 * simultaneously, so part_constraint() is not needed on this path.
+	 */
+	if (cpuc->excl_cntrs) {
+		WARN_ON_ONCE(x86_pmu_partition_loaded(cpuc));
 		return intel_get_excl_constraints(cpuc, event, idx, c2);
+	}
 
 	if (event->hw.dyn_constraint != ~0ULL) {
 		c2 = dyn_constraint(cpuc, c2, idx);
@@ -4578,7 +4616,7 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
 		c2->weight = hweight64(c2->idxmsk64);
 	}
 
-	return c2;
+	return part_constraint(cpuc, idx, event, c2);
 }
 
 static void intel_put_excl_constraints(struct cpu_hw_events *cpuc,
@@ -5948,7 +5986,8 @@ int intel_cpuc_prepare(struct cpu_hw_events *cpuc, int cpu)
 			goto err;
 	}
 
-	if (x86_pmu.flags & (PMU_FL_EXCL_CNTRS | PMU_FL_TFA | PMU_FL_DYN_CONSTRAINT)) {
+	if (x86_pmu.flags & (PMU_FL_EXCL_CNTRS | PMU_FL_TFA | PMU_FL_DYN_CONSTRAINT) ||
+	    (x86_get_pmu(cpu)->capabilities & PERF_PMU_CAP_MEDIATED_VPMU)) {
 		size_t sz = X86_PMC_IDX_MAX * sizeof(struct event_constraint);
 
 		cpuc->constraint_list = kzalloc_node(sz, GFP_KERNEL, cpu_to_node(cpu));
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.