Convert the list of PMUs to a RCU-protected list that has primitives to
avoid read-side contention.

Assisted-by: Codex:gpt-5.5
Signed-off-by: Akihiko Odaki <[email protected]>
---
 arch/arm64/kvm/pmu-emul.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index c816db5d6761..68fce960ba69 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -7,9 +7,9 @@
 #include <linux/cpu.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
-#include <linux/list.h>
 #include <linux/perf_event.h>
 #include <linux/perf/arm_pmu.h>
+#include <linux/rculist.h>
 #include <linux/uaccess.h>
 #include <asm/kvm_emulate.h>
 #include <kvm/arm_pmu.h>
@@ -17,6 +17,10 @@
 
 #define PERF_ATTR_CFG1_COUNTER_64BIT   BIT(0)
 
+/*
+ * arm_pmus is append-only. kvm_supports_guest_pmuv3() feeds persistent
+ * VM state, so a true result must remain valid after the check.
+ */
 static LIST_HEAD(arm_pmus);
 static DEFINE_MUTEX(arm_pmus_lock);
 
@@ -26,7 +30,6 @@ static bool kvm_pmu_counter_is_enabled(struct kvm_pmc *pmc);
 
 bool kvm_supports_guest_pmuv3(void)
 {
-       guard(mutex)(&arm_pmus_lock);
        return !list_empty(&arm_pmus);
 }
 
@@ -802,7 +805,7 @@ void kvm_host_pmu_init(struct arm_pmu *pmu)
                return;
 
        entry->arm_pmu = pmu;
-       list_add_tail(&entry->entry, &arm_pmus);
+       list_add_tail_rcu(&entry->entry, &arm_pmus);
 }
 
 static struct arm_pmu *kvm_pmu_probe_armpmu(void)
@@ -811,7 +814,7 @@ static struct arm_pmu *kvm_pmu_probe_armpmu(void)
        struct arm_pmu *pmu;
        int cpu;
 
-       guard(mutex)(&arm_pmus_lock);
+       guard(rcu)();
 
        /*
         * It is safe to use a stale cpu to iterate the list of PMUs so long as
@@ -831,7 +834,7 @@ static struct arm_pmu *kvm_pmu_probe_armpmu(void)
         * carried here.
         */
        cpu = raw_smp_processor_id();
-       list_for_each_entry(entry, &arm_pmus, entry) {
+       list_for_each_entry_rcu(entry, &arm_pmus, entry) {
                pmu = entry->arm_pmu;
 
                if (cpumask_test_cpu(cpu, &pmu->supported_cpus))
@@ -1092,9 +1095,9 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, 
int pmu_id)
        int ret = -ENXIO;
 
        lockdep_assert_held(&kvm->arch.config_lock);
-       mutex_lock(&arm_pmus_lock);
+       guard(rcu)();
 
-       list_for_each_entry(entry, &arm_pmus, entry) {
+       list_for_each_entry_rcu(entry, &arm_pmus, entry) {
                arm_pmu = entry->arm_pmu;
                if (arm_pmu->pmu.type == pmu_id) {
                        if (kvm_vm_has_ran_once(kvm) ||
@@ -1110,7 +1113,6 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, 
int pmu_id)
                }
        }
 
-       mutex_unlock(&arm_pmus_lock);
        return ret;
 }
 

-- 
2.55.0


Reply via email to