mainline inclusion from mainline-v7.1-rc1 commit a4c6c18e93a1d24df9ab95794cef471c89daefe4 category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/9134 CVE: NA Reference: https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commi... ---------------------------------------------------------------------- The cpuidle_unregister_device() function always acquires the internal cpuidle_lock (or pause/resume idle) during their execution. However, in some power notification scenarios (e.g., when old idle states may become unavailable), it is necessary to efficiently disable cpuidle first, then remove and re-create all cpuidle devices for all CPUs. To avoid frequent lock overhead and ensure atomicity across the entire batch operation, the caller needs to hold the cpuidle_lock once outside the loop. To address this, extract the core logic into the new function cpuidle_unregister_device_no_lock() and export it. Signed-off-by: Huisong Li <lihuisong@huawei.com> [ rjw: Added missing "inline", subject and changelog tweaks ] Link: https://patch.msgid.link/20260407081141.2493581-2-lihuisong@huawei.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Huisong Li <lihuisong@huawei.com> Signed-off-by: Hongye Lin <linhongye@h-partners.com> --- drivers/cpuidle/cpuidle.c | 22 +++++++++++++++------- include/linux/cpuidle.h | 2 ++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 0c02fee8d720..ac21621b298a 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -709,16 +709,12 @@ int cpuidle_register_device(struct cpuidle_device *dev) EXPORT_SYMBOL_GPL(cpuidle_register_device); -/** - * cpuidle_unregister_device - unregisters a CPU's idle PM feature - * @dev: the cpu - */ -void cpuidle_unregister_device(struct cpuidle_device *dev) +void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev) { if (!dev || dev->registered == 0) return; - cpuidle_pause_and_lock(); + lockdep_assert_held(&cpuidle_lock); cpuidle_disable_device(dev); @@ -727,10 +723,22 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) __cpuidle_unregister_device(dev); cpuidle_coupled_unregister_device(dev); +} +EXPORT_SYMBOL_GPL(cpuidle_unregister_device_no_lock); + +/** + * cpuidle_unregister_device - unregisters a CPU's idle PM feature + * @dev: the cpu + */ +void cpuidle_unregister_device(struct cpuidle_device *dev) +{ + if (!dev || dev->registered == 0) + return; + cpuidle_pause_and_lock(); + cpuidle_unregister_device_no_lock(dev); cpuidle_resume_and_unlock(); } - EXPORT_SYMBOL_GPL(cpuidle_unregister_device); /** diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 7e7e58a17b07..b348c13e8ac4 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -188,6 +188,7 @@ extern void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx, extern void cpuidle_unregister_driver(struct cpuidle_driver *drv); extern int cpuidle_register_device(struct cpuidle_device *dev); extern void cpuidle_unregister_device(struct cpuidle_device *dev); +extern void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev); extern int cpuidle_register(struct cpuidle_driver *drv, const struct cpumask *const coupled_cpus); extern void cpuidle_unregister(struct cpuidle_driver *drv); @@ -226,6 +227,7 @@ static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { } static inline int cpuidle_register_device(struct cpuidle_device *dev) {return -ENODEV; } static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { } +static inline void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev) {} static inline int cpuidle_register(struct cpuidle_driver *drv, const struct cpumask *const coupled_cpus) {return -ENODEV; } -- 2.33.0