diff options
author | Ulf Hansson <ulf.hansson@linaro.org> | 2015-01-27 15:13:43 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-03 16:56:54 -0500 |
commit | 3e235685de3f7e53e17d671b2379df10c6dfa4f2 (patch) | |
tree | e0f49a6a702b6f752cbcd2e740e96c14c47e208c /drivers/base/power | |
parent | c0356db7d1b66840882744cbd9d9c5960b2d88c7 (diff) |
PM / Domains: Free pm_subsys_data in error path in __pm_genpd_add_device()
The error path in __pm_genpd_add_device() didn't decrease the reference
to the struct pm_subsys_data.
Let's move the calls to dev_pm_get|put_subsys_data() into
genpd_alloc|free_dev_data() to fix this issue and thus prevent a
potential memory leakage.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/base/power')
-rw-r--r-- | drivers/base/power/domain.c | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 1f026c18bc5c..3bd342f22519 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -1380,18 +1380,30 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); | |||
1380 | static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) | 1380 | static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) |
1381 | { | 1381 | { |
1382 | struct generic_pm_domain_data *gpd_data; | 1382 | struct generic_pm_domain_data *gpd_data; |
1383 | int ret; | ||
1384 | |||
1385 | ret = dev_pm_get_subsys_data(dev); | ||
1386 | if (ret) | ||
1387 | return ERR_PTR(ret); | ||
1383 | 1388 | ||
1384 | gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL); | 1389 | gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL); |
1385 | if (!gpd_data) | 1390 | if (!gpd_data) { |
1386 | return NULL; | 1391 | ret = -ENOMEM; |
1392 | goto err_put; | ||
1393 | } | ||
1387 | 1394 | ||
1388 | return gpd_data; | 1395 | return gpd_data; |
1396 | |||
1397 | err_put: | ||
1398 | dev_pm_put_subsys_data(dev); | ||
1399 | return ERR_PTR(ret); | ||
1389 | } | 1400 | } |
1390 | 1401 | ||
1391 | static void genpd_free_dev_data(struct device *dev, | 1402 | static void genpd_free_dev_data(struct device *dev, |
1392 | struct generic_pm_domain_data *gpd_data) | 1403 | struct generic_pm_domain_data *gpd_data) |
1393 | { | 1404 | { |
1394 | kfree(gpd_data); | 1405 | kfree(gpd_data); |
1406 | dev_pm_put_subsys_data(dev); | ||
1395 | } | 1407 | } |
1396 | 1408 | ||
1397 | /** | 1409 | /** |
@@ -1412,8 +1424,8 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | |||
1412 | return -EINVAL; | 1424 | return -EINVAL; |
1413 | 1425 | ||
1414 | gpd_data = genpd_alloc_dev_data(dev); | 1426 | gpd_data = genpd_alloc_dev_data(dev); |
1415 | if (!gpd_data) | 1427 | if (IS_ERR(gpd_data)) |
1416 | return -ENOMEM; | 1428 | return PTR_ERR(gpd_data); |
1417 | 1429 | ||
1418 | genpd_acquire_lock(genpd); | 1430 | genpd_acquire_lock(genpd); |
1419 | 1431 | ||
@@ -1422,10 +1434,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | |||
1422 | goto out; | 1434 | goto out; |
1423 | } | 1435 | } |
1424 | 1436 | ||
1425 | ret = dev_pm_get_subsys_data(dev); | ||
1426 | if (ret) | ||
1427 | goto out; | ||
1428 | |||
1429 | spin_lock_irq(&dev->power.lock); | 1437 | spin_lock_irq(&dev->power.lock); |
1430 | 1438 | ||
1431 | if (dev->power.subsys_data->domain_data) { | 1439 | if (dev->power.subsys_data->domain_data) { |
@@ -1528,7 +1536,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1528 | 1536 | ||
1529 | genpd_release_lock(genpd); | 1537 | genpd_release_lock(genpd); |
1530 | 1538 | ||
1531 | dev_pm_put_subsys_data(dev); | ||
1532 | genpd_free_dev_data(dev, gpd_data); | 1539 | genpd_free_dev_data(dev, gpd_data); |
1533 | 1540 | ||
1534 | return 0; | 1541 | return 0; |