[PATCH] pm/opp: fix race between opp_add and opp_get
From: Xuewen Yan
Date: Mon Apr 27 2026 - 08:05:38 EST
From: Di Shen <di.shen@xxxxxxxxxx>
There is a race between opp_table_find_key and dev_pm_opp_add_dynamic:
dev_pm_opp_add_dynamic dev_pm_opp_find_freq_exact
_opp_add_v1 _find_key
_opp_add _opp_table_find_key
mutex_lock(opp_table->lock)
list_add(&new_opp->node, head)
mutex_unlock(opp_table->lock)
mutex_lock(opp_table->lock)
dev_pm_opp_get(opp)
kref_get(&opp->kref)
refcount_inc(&kref->refcount);
mutex_unlock(opp_table->lock)
kref_init(&new_opp->kref)
refcount_set(&kref->refcount, 1);
dev_pm_opp_put()
kref_put_mutex()
This would cause the opp be freed.
So use the mutex to protect opp's ref count.
Co-developed-by: Ling Xu <ling_ling.xu@xxxxxxxxxx>
Signed-off-by: Ling Xu <ling_ling.xu@xxxxxxxxxx>
Signed-off-by: Di Shen <di.shen@xxxxxxxxxx>
---
drivers/opp/core.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 866641666e41..34cdcf8f598d 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -2088,11 +2088,10 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
return ret;
list_add(&new_opp->node, head);
+ new_opp->opp_table = opp_table;
+ kref_init(&new_opp->kref);
}
- new_opp->opp_table = opp_table;
- kref_init(&new_opp->kref);
-
opp_debug_create_one(new_opp, opp_table);
if (!_opp_supported_by_regulators(new_opp, opp_table)) {
--
2.25.1