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 --- 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