aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/domain.c
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2015-01-27 15:13:43 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-03 16:56:54 -0500
commit3e235685de3f7e53e17d671b2379df10c6dfa4f2 (patch)
treee0f49a6a702b6f752cbcd2e740e96c14c47e208c /drivers/base/power/domain.c
parentc0356db7d1b66840882744cbd9d9c5960b2d88c7 (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/domain.c')
-rw-r--r--drivers/base/power/domain.c25
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);
1380static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev) 1380static 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
1391static void genpd_free_dev_data(struct device *dev, 1402static 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;