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 | |
| 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')
| -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; |
