[PATCH kvmtool 4/7] arm64/pmu: Consider kvmtool's affinity when searching for a PMU

Alexandru Elisei alexandru.elisei at arm.com
Thu Sep 17 08:49:29 PDT 2026


When --vcpu-affinity is set, find_pmu() -> find_pmu_cpumask() attempts to
find a PMU instance that is shared by all CPUs in the specified affinity.

If --vcpu-affinity is not set, find_pmu() will only attempt to find a PMU
instance associated with the *current* physical CPU. This misses the fact
that it might be possible that the other threads that kvmtool creates
(which include the VCPU threads), might be executed on physical CPUs which
have a different PMU instance than the *current* physical CPU (or none at
all). This can lead to hard to reproduce and diagnose errors.

Improve things by teaching find_pmu() to use kvmtool process CPU affinity
when --vcpu-affinity is not set.

Also fix a memory leak by freeing the local variable 'cpumask'.

Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
 arm64/pmu.c | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/arm64/pmu.c b/arm64/pmu.c
index e5a07abcd317..d3761689c907 100644
--- a/arm64/pmu.c
+++ b/arm64/pmu.c
@@ -189,28 +189,44 @@ out_free:
  */
 static int find_pmu(struct kvm *kvm)
 {
+	cpu_set_t *affinity;
 	cpumask_t *cpumask;
-	int i, this_cpu;
 	size_t setsize;
+	int i, ret = 0;
 
 	cpumask = calloc(cpumask_size(), 1);
 	if (!cpumask)
 		die_perror("calloc");
 
-	if (!kvm->arch.vcpu_affinity_cpuset) {
-		this_cpu = sched_getcpu();
-		if (this_cpu < 0)
-			return -errno;
-		cpumask_set_cpu(this_cpu, cpumask);
+	setsize = CPU_ALLOC_SIZE(NR_CPUS);
+
+	if (kvm->arch.vcpu_affinity_cpuset) {
+		affinity = kvm->arch.vcpu_affinity_cpuset;
 	} else {
-		setsize = CPU_ALLOC_SIZE(NR_CPUS);
-		for (i = 0; i < NR_CPUS; i ++) {
-			if (CPU_ISSET_S(i, setsize, kvm->arch.vcpu_affinity_cpuset))
-				cpumask_set_cpu(i, cpumask);
+		affinity = CPU_ALLOC(NR_CPUS);
+		if (!affinity)
+			die_perror("CPU_ALLOC");
+		CPU_ZERO_S(setsize, affinity);
+
+		ret = sched_getaffinity(0, setsize, affinity);
+		if (ret < 0) {
+			ret = -errno;
+			goto out_free;
 		}
 	}
 
-	return find_pmu_cpumask(kvm, cpumask);
+	for (i = 0; i < NR_CPUS; i ++) {
+		if (CPU_ISSET_S(i, setsize, affinity))
+			cpumask_set_cpu(i, cpumask);
+	}
+
+	ret = find_pmu_cpumask(kvm, cpumask);
+
+out_free:
+	free(cpumask);
+	if (!kvm->arch.vcpu_affinity_cpuset)
+		CPU_FREE(affinity);
+	return ret;
 }
 
 void pmu__generate_fdt_nodes(void *fdt, struct kvm *kvm)
-- 
2.55.0




More information about the linux-arm-kernel mailing list