Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powercap: intel_rapl: Fix possible recursive lock warning

With the RAPL PMU addition, there is a recursive locking when CPU online
callback function calls rapl_package_add_pmu(). Here cpu_hotplug_lock
is already acquired by cpuhp_thread_fun() and rapl_package_add_pmu()
tries to acquire again.

<4>[ 8.197433] ============================================
<4>[ 8.197437] WARNING: possible recursive locking detected
<4>[ 8.197440] 6.19.0-rc1-lgci-xe-xe-4242-05b7c58b3367dca84+ #1 Not tainted
<4>[ 8.197444] --------------------------------------------
<4>[ 8.197447] cpuhp/0/20 is trying to acquire lock:
<4>[ 8.197450] ffffffff83487870 (cpu_hotplug_lock){++++}-{0:0}, at:
rapl_package_add_pmu+0x37/0x370 [intel_rapl_common]
<4>[ 8.197463]
but task is already holding lock:
<4>[ 8.197466] ffffffff83487870 (cpu_hotplug_lock){++++}-{0:0}, at:
cpuhp_thread_fun+0x6d/0x290
<4>[ 8.197477]
other info that might help us debug this:
<4>[ 8.197480] Possible unsafe locking scenario:

<4>[ 8.197483] CPU0
<4>[ 8.197485] ----
<4>[ 8.197487] lock(cpu_hotplug_lock);
<4>[ 8.197490] lock(cpu_hotplug_lock);
<4>[ 8.197493]
*** DEADLOCK ***
..
..
<4>[ 8.197542] __lock_acquire+0x146e/0x2790
<4>[ 8.197548] lock_acquire+0xc4/0x2c0
<4>[ 8.197550] ? rapl_package_add_pmu+0x37/0x370 [intel_rapl_common]
<4>[ 8.197556] cpus_read_lock+0x41/0x110
<4>[ 8.197558] ? rapl_package_add_pmu+0x37/0x370 [intel_rapl_common]
<4>[ 8.197561] rapl_package_add_pmu+0x37/0x370 [intel_rapl_common]
<4>[ 8.197565] rapl_cpu_online+0x85/0x87 [intel_rapl_msr]
<4>[ 8.197568] ? __pfx_rapl_cpu_online+0x10/0x10 [intel_rapl_msr]
<4>[ 8.197570] cpuhp_invoke_callback+0x41f/0x6c0
<4>[ 8.197573] ? cpuhp_thread_fun+0x6d/0x290
<4>[ 8.197575] cpuhp_thread_fun+0x1e2/0x290
<4>[ 8.197578] ? smpboot_thread_fn+0x26/0x290
<4>[ 8.197581] smpboot_thread_fn+0x12f/0x290
<4>[ 8.197584] ? __pfx_smpboot_thread_fn+0x10/0x10
<4>[ 8.197586] kthread+0x11f/0x250
<4>[ 8.197589] ? __pfx_kthread+0x10/0x10
<4>[ 8.197592] ret_from_fork+0x344/0x3a0
<4>[ 8.197595] ? __pfx_kthread+0x10/0x10
<4>[ 8.197597] ret_from_fork_asm+0x1a/0x30
<4>[ 8.197604] </TASK>

Fix this issue in the same way as rapl powercap package domain is added
from the same CPU online callback by introducing another interface which
doesn't call cpus_read_lock(). Add rapl_package_add_pmu_locked() and
rapl_package_remove_pmu_locked() which don't call cpus_read_lock().

Fixes: 748d6ba43afd ("powercap: intel_rapl: Enable MSR-based RAPL PMU support")
Reported-by: Borah, Chaitanya Kumar <chaitanya.kumar.borah@intel.com>
Closes: https://lore.kernel.org/linux-pm/5427ede1-57a0-43d1-99f3-8ca4b0643e82@intel.com/T/#u
Tested-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Tested-by: RavitejaX Veesam <ravitejax.veesam@intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Link: https://patch.msgid.link/20251217153455.3560176-1-srinivas.pandruvada@linux.intel.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Srinivas Pandruvada and committed by
Rafael J. Wysocki
dcd0b625 efc4c35b

+24 -8
+18 -6
drivers/powercap/intel_rapl_common.c
··· 2032 2032 return ret; 2033 2033 } 2034 2034 2035 - int rapl_package_add_pmu(struct rapl_package *rp) 2035 + int rapl_package_add_pmu_locked(struct rapl_package *rp) 2036 2036 { 2037 2037 struct rapl_package_pmu_data *data = &rp->pmu_data; 2038 2038 int idx; 2039 2039 2040 2040 if (rp->has_pmu) 2041 2041 return -EEXIST; 2042 - 2043 - guard(cpus_read_lock)(); 2044 2042 2045 2043 for (idx = 0; idx < rp->nr_domains; idx++) { 2046 2044 struct rapl_domain *rd = &rp->domains[idx]; ··· 2089 2091 2090 2092 return rapl_pmu_update(rp); 2091 2093 } 2094 + EXPORT_SYMBOL_GPL(rapl_package_add_pmu_locked); 2095 + 2096 + int rapl_package_add_pmu(struct rapl_package *rp) 2097 + { 2098 + guard(cpus_read_lock)(); 2099 + 2100 + return rapl_package_add_pmu_locked(rp); 2101 + } 2092 2102 EXPORT_SYMBOL_GPL(rapl_package_add_pmu); 2093 2103 2094 - void rapl_package_remove_pmu(struct rapl_package *rp) 2104 + void rapl_package_remove_pmu_locked(struct rapl_package *rp) 2095 2105 { 2096 2106 struct rapl_package *pos; 2097 2107 2098 2108 if (!rp->has_pmu) 2099 2109 return; 2100 - 2101 - guard(cpus_read_lock)(); 2102 2110 2103 2111 list_for_each_entry(pos, &rapl_packages, plist) { 2104 2112 /* PMU is still needed */ ··· 2114 2110 2115 2111 perf_pmu_unregister(&rapl_pmu.pmu); 2116 2112 memset(&rapl_pmu, 0, sizeof(struct rapl_pmu)); 2113 + } 2114 + EXPORT_SYMBOL_GPL(rapl_package_remove_pmu_locked); 2115 + 2116 + void rapl_package_remove_pmu(struct rapl_package *rp) 2117 + { 2118 + guard(cpus_read_lock)(); 2119 + 2120 + rapl_package_remove_pmu_locked(rp); 2117 2121 } 2118 2122 EXPORT_SYMBOL_GPL(rapl_package_remove_pmu); 2119 2123 #endif
+2 -2
drivers/powercap/intel_rapl_msr.c
··· 82 82 if (IS_ERR(rp)) 83 83 return PTR_ERR(rp); 84 84 if (rapl_msr_pmu) 85 - rapl_package_add_pmu(rp); 85 + rapl_package_add_pmu_locked(rp); 86 86 } 87 87 cpumask_set_cpu(cpu, &rp->cpumask); 88 88 return 0; ··· 101 101 lead_cpu = cpumask_first(&rp->cpumask); 102 102 if (lead_cpu >= nr_cpu_ids) { 103 103 if (rapl_msr_pmu) 104 - rapl_package_remove_pmu(rp); 104 + rapl_package_remove_pmu_locked(rp); 105 105 rapl_remove_package_cpuslocked(rp); 106 106 } else if (rp->lead_cpu == cpu) { 107 107 rp->lead_cpu = lead_cpu;
+4
include/linux/intel_rapl.h
··· 214 214 215 215 #ifdef CONFIG_PERF_EVENTS 216 216 int rapl_package_add_pmu(struct rapl_package *rp); 217 + int rapl_package_add_pmu_locked(struct rapl_package *rp); 217 218 void rapl_package_remove_pmu(struct rapl_package *rp); 219 + void rapl_package_remove_pmu_locked(struct rapl_package *rp); 218 220 #else 219 221 static inline int rapl_package_add_pmu(struct rapl_package *rp) { return 0; } 222 + static inline int rapl_package_add_pmu_locked(struct rapl_package *rp) { return 0; } 220 223 static inline void rapl_package_remove_pmu(struct rapl_package *rp) { } 224 + static inline void rapl_package_remove_pmu_locked(struct rapl_package *rp) { } 221 225 #endif 222 226 223 227 #endif /* __INTEL_RAPL_H__ */