powercap: intel_rapl: Fix locking in TPMI RAPL
authorZhang Rui <rui.zhang@intel.com>
Wed, 31 Jan 2024 11:37:09 +0000 (19:37 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 13 Feb 2024 16:31:48 +0000 (17:31 +0100)
The RAPL framework uses CPU hotplug locking to protect the rapl_packages
list and rp->lead_cpu to guarantee that

 1. the RAPL package device is not unprobed and freed
 2. the cached rp->lead_cpu is always valid

for operations like powercap sysfs accesses.

Current RAPL APIs assume being called from CPU hotplug callbacks which
hold the CPU hotplug lock, but TPMI RAPL driver invokes the APIs in the
driver's .probe() function without acquiring the CPU hotplug lock.

Fix the problem by providing both locked and lockless versions of RAPL
APIs.

Fixes: 9eef7f9da928 ("powercap: intel_rapl: Introduce RAPL TPMI interface driver")
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Cc: 6.5+ <stable@vger.kernel.org> # 6.5+
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/powercap/intel_rapl_common.c
drivers/powercap/intel_rapl_msr.c
drivers/thermal/intel/int340x_thermal/processor_thermal_rapl.c
include/linux/intel_rapl.h

index 1a739afd47d965aac064b531237c9f166f938e86..9d3e102f1a76b64bf8dab9cf45ea278c71307480 100644 (file)
@@ -5,6 +5,7 @@
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/cleanup.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/list.h>
@@ -1504,7 +1505,7 @@ static int rapl_detect_domains(struct rapl_package *rp)
 }
 
 /* called from CPU hotplug notifier, hotplug lock held */
-void rapl_remove_package(struct rapl_package *rp)
+void rapl_remove_package_cpuslocked(struct rapl_package *rp)
 {
        struct rapl_domain *rd, *rd_package = NULL;
 
@@ -1533,10 +1534,18 @@ void rapl_remove_package(struct rapl_package *rp)
        list_del(&rp->plist);
        kfree(rp);
 }
+EXPORT_SYMBOL_GPL(rapl_remove_package_cpuslocked);
+
+void rapl_remove_package(struct rapl_package *rp)
+{
+       guard(cpus_read_lock)();
+       rapl_remove_package_cpuslocked(rp);
+}
 EXPORT_SYMBOL_GPL(rapl_remove_package);
 
 /* caller to ensure CPU hotplug lock is held */
-struct rapl_package *rapl_find_package_domain(int id, struct rapl_if_priv *priv, bool id_is_cpu)
+struct rapl_package *rapl_find_package_domain_cpuslocked(int id, struct rapl_if_priv *priv,
+                                                        bool id_is_cpu)
 {
        struct rapl_package *rp;
        int uid;
@@ -1554,10 +1563,17 @@ struct rapl_package *rapl_find_package_domain(int id, struct rapl_if_priv *priv,
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(rapl_find_package_domain_cpuslocked);
+
+struct rapl_package *rapl_find_package_domain(int id, struct rapl_if_priv *priv, bool id_is_cpu)
+{
+       guard(cpus_read_lock)();
+       return rapl_find_package_domain_cpuslocked(id, priv, id_is_cpu);
+}
 EXPORT_SYMBOL_GPL(rapl_find_package_domain);
 
 /* called from CPU hotplug notifier, hotplug lock held */
-struct rapl_package *rapl_add_package(int id, struct rapl_if_priv *priv, bool id_is_cpu)
+struct rapl_package *rapl_add_package_cpuslocked(int id, struct rapl_if_priv *priv, bool id_is_cpu)
 {
        struct rapl_package *rp;
        int ret;
@@ -1603,6 +1619,13 @@ err_free_package:
        kfree(rp);
        return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_GPL(rapl_add_package_cpuslocked);
+
+struct rapl_package *rapl_add_package(int id, struct rapl_if_priv *priv, bool id_is_cpu)
+{
+       guard(cpus_read_lock)();
+       return rapl_add_package_cpuslocked(id, priv, id_is_cpu);
+}
 EXPORT_SYMBOL_GPL(rapl_add_package);
 
 static void power_limit_state_save(void)
index 250bd41a588c7d97f8cc3edbd85258f8dd244412..b4b6930cacb0b11b016c771b2301a4c8f416f707 100644 (file)
@@ -73,9 +73,9 @@ static int rapl_cpu_online(unsigned int cpu)
 {
        struct rapl_package *rp;
 
-       rp = rapl_find_package_domain(cpu, rapl_msr_priv, true);
+       rp = rapl_find_package_domain_cpuslocked(cpu, rapl_msr_priv, true);
        if (!rp) {
-               rp = rapl_add_package(cpu, rapl_msr_priv, true);
+               rp = rapl_add_package_cpuslocked(cpu, rapl_msr_priv, true);
                if (IS_ERR(rp))
                        return PTR_ERR(rp);
        }
@@ -88,14 +88,14 @@ static int rapl_cpu_down_prep(unsigned int cpu)
        struct rapl_package *rp;
        int lead_cpu;
 
-       rp = rapl_find_package_domain(cpu, rapl_msr_priv, true);
+       rp = rapl_find_package_domain_cpuslocked(cpu, rapl_msr_priv, true);
        if (!rp)
                return 0;
 
        cpumask_clear_cpu(cpu, &rp->cpumask);
        lead_cpu = cpumask_first(&rp->cpumask);
        if (lead_cpu >= nr_cpu_ids)
-               rapl_remove_package(rp);
+               rapl_remove_package_cpuslocked(rp);
        else if (rp->lead_cpu == cpu)
                rp->lead_cpu = lead_cpu;
        return 0;
index 2f00fc3bf274a33255b1308de7772f1752c2c638..e964a9375722ad968f51c2c2d471863c35fc5de1 100644 (file)
@@ -27,9 +27,9 @@ static int rapl_mmio_cpu_online(unsigned int cpu)
        if (topology_physical_package_id(cpu))
                return 0;
 
-       rp = rapl_find_package_domain(cpu, &rapl_mmio_priv, true);
+       rp = rapl_find_package_domain_cpuslocked(cpu, &rapl_mmio_priv, true);
        if (!rp) {
-               rp = rapl_add_package(cpu, &rapl_mmio_priv, true);
+               rp = rapl_add_package_cpuslocked(cpu, &rapl_mmio_priv, true);
                if (IS_ERR(rp))
                        return PTR_ERR(rp);
        }
@@ -42,14 +42,14 @@ static int rapl_mmio_cpu_down_prep(unsigned int cpu)
        struct rapl_package *rp;
        int lead_cpu;
 
-       rp = rapl_find_package_domain(cpu, &rapl_mmio_priv, true);
+       rp = rapl_find_package_domain_cpuslocked(cpu, &rapl_mmio_priv, true);
        if (!rp)
                return 0;
 
        cpumask_clear_cpu(cpu, &rp->cpumask);
        lead_cpu = cpumask_first(&rp->cpumask);
        if (lead_cpu >= nr_cpu_ids)
-               rapl_remove_package(rp);
+               rapl_remove_package_cpuslocked(rp);
        else if (rp->lead_cpu == cpu)
                rp->lead_cpu = lead_cpu;
        return 0;
index 33f21bd85dbf273eb98b4095e81351c57894af9d..f3196f82fd8a14364b09490a6e1ac46a2c55b0e9 100644 (file)
@@ -178,6 +178,12 @@ struct rapl_package {
        struct rapl_if_priv *priv;
 };
 
+struct rapl_package *rapl_find_package_domain_cpuslocked(int id, struct rapl_if_priv *priv,
+                                                      bool id_is_cpu);
+struct rapl_package *rapl_add_package_cpuslocked(int id, struct rapl_if_priv *priv,
+                                                bool id_is_cpu);
+void rapl_remove_package_cpuslocked(struct rapl_package *rp);
+
 struct rapl_package *rapl_find_package_domain(int id, struct rapl_if_priv *priv, bool id_is_cpu);
 struct rapl_package *rapl_add_package(int id, struct rapl_if_priv *priv, bool id_is_cpu);
 void rapl_remove_package(struct rapl_package *rp);