mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
PM / Domains: Fix potential deadlock while adding/removing subdomains
We must preserve the same order of how we acquire and release the lock for genpd, as otherwise we may encounter deadlocks. The power on phase of a genpd starts by acquiring its lock. Then it walks the hierarchy of its parent domains to be able to power on these first, as per design of genpd. From a locking perspective this means the locks of the parents becomes acquired after the lock of the subdomain. Let's fix pm_genpd_add|remove_subdomain() to maintain the same order of acquiring/releasing the genpd lock as being applied in the power on/off sequence. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
0106ef5146
commit
cdb300a041
1 changed files with 6 additions and 8 deletions
|
@ -1340,8 +1340,8 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
|||
if (!link)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&genpd->lock);
|
||||
mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
|
||||
mutex_lock(&subdomain->lock);
|
||||
mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
|
||||
|
||||
if (genpd->status == GPD_STATE_POWER_OFF
|
||||
&& subdomain->status != GPD_STATE_POWER_OFF) {
|
||||
|
@ -1364,8 +1364,8 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
|||
genpd_sd_counter_inc(genpd);
|
||||
|
||||
out:
|
||||
mutex_unlock(&subdomain->lock);
|
||||
mutex_unlock(&genpd->lock);
|
||||
mutex_unlock(&subdomain->lock);
|
||||
if (ret)
|
||||
kfree(link);
|
||||
return ret;
|
||||
|
@ -1386,7 +1386,8 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
|||
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&genpd->lock);
|
||||
mutex_lock(&subdomain->lock);
|
||||
mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
|
||||
|
||||
if (!list_empty(&subdomain->slave_links) || subdomain->device_count) {
|
||||
pr_warn("%s: unable to remove subdomain %s\n", genpd->name,
|
||||
|
@ -1399,22 +1400,19 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
|||
if (link->slave != subdomain)
|
||||
continue;
|
||||
|
||||
mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
|
||||
|
||||
list_del(&link->master_node);
|
||||
list_del(&link->slave_node);
|
||||
kfree(link);
|
||||
if (subdomain->status != GPD_STATE_POWER_OFF)
|
||||
genpd_sd_counter_dec(genpd);
|
||||
|
||||
mutex_unlock(&subdomain->lock);
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&genpd->lock);
|
||||
mutex_unlock(&subdomain->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue